/**
  ******************************************************************************
  * @file    device_controller.c
  * @author  zhuang
  * @version 1.0.0
  * @date    2021/1/20
  * @brief   
  ******************************************************************************
  * @attention
  *
  *
  ******************************************************************************
  */ 
  
/* Includes ------------------------------------------------------------------*/
#include <stdlib.h>
#include <math.h>
#include "mlink.h"

#include "mesh_router_common.h"
#include "device_controller.h"
#include "mlink_handle.h"
#include "mesh_mqtt_handle.h"
#include "mlink_mqtt_handle.h"
#include "dlt645_api_07.h"
#include "dlt645_port.h"
#include "dlt645_api_07_test.h"
#include "dlt645_api_97.h"
#include "cjt188_api_04.h"
#include "mb_app.h"
#include "device_handle.h"
#include "board_common.h"
#include "iot_board.h"
#include "driver_adc.h"
#include "mlink_subdevice.h"
#include "ntc_sensor.h"

/* Public variables ----------------------------------------------------------*/
uint16_t DEVICE_TID;
// extern mb_app_t *g_mb_handle[SUBDEV_PORT_MAX_NUM];
// extern dlt645_t *g_dlt645_handle[SUBDEV_PORT_MAX_NUM];
// subdev_port_t g_subdev_port[SUBDEV_PORT_MAX_NUM];
/* Public functions ----------------------------------------------------------*/
extern int write_cid_to_report_queue(subdev_port_t *subdev_port, subdev_cid_t *subdev_cid, int timeout);

/* Private typedef -----------------------------------------------------------*/
// typedef struct {
//     char ssid[33];
//     char password[65];
// 	bool ssid_hide; // 0:不隐藏ssid 1:隐藏ssid
// 	bool disable; // 0:开启wifi 1:关闭wifi
// } device_wifi_ap_config_t;

/* Private define ------------------------------------------------------------*/
#define DEVICE_CONFIG_STORE_KEY              "device_config"
#define DEVICE_REBOOT_TIME_STORE_KEY         "reboot_time"
#define DEVICE_REPORT_TIME_STORE_KEY         "reboot_time"
#define DEVICE_MODE_STORE_KEY                "dev_mode"
#define DEVICE_DEVICE_SN_STORE_KEY       "device_sn"

#define DEVICE_MESH_ADDR_STORE_KEY           "mesh_addr"
// #define STATIC_IP_STORE_KEY                  "static_ip"
// #define STATIC_NETMASK_STORE_KEY             "static_netmask"
// #define STATIC_GW_STORE_KEY                  "static_gw"
// #define STATIC_IP_ENABLE_STORE_KEY           "static_enable"
// #define WEB_USER_PASSWORD_STORE_KEY          "web_password"
// #define DEVICE_SSID_PASSWORD_STORE_KEY       "ssid_password"
// #define DEVICE_WIFI_CHANNEL_STORE_KEY        "wifi_channel"
// #define DEVICE_DLT645_PASS_STORE_KEY         "dlt645_pass"
#define DEVICE_SUBDEV_INFO_STORE_KEY         "subdev_info"
#define DEVICE_DEFAULT_NETIF_STORE_KEY       "default_netif"
#define DEVICE_IO_DO_STATUS_STORE_KEY           "do_status"

/* Private macro -------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/
static const char *TAG = "device";
static char g_device_sn[16]="";
static uint8_t g_mesh_addr[6]={0,0,0,0,0,0};
static bool g_mesh_id_is_set = false;
static int g_reboot_time=7200;  // 重启时间，从0点开始计算经过的秒钟数，>0:有效, 0:不自动重启
static int g_report_time=600;  // 周期上报时间
static int g_mode = DEVICE_MODE_AIR_SWITCH_HEY;

// static char g_dlt645_password[10]="02000000"; // DLT645 password
static float g_temperature;

// static char g_static_ip[16] = {0};
// static char g_static_netmask[16] = {0};
// static char g_static_gw[16] = {0};
// static uint8_t g_static_ip_enable = false;
// static char g_web_user_password[16]="admin";
// static device_wifi_ap_config_t g_wifi_ap_cfg={0};
// static uint8_t g_wifi_channel=0; // wifi信道 0-13，-1:不指定信道
static char g_dt_target_ip[16];
static int g_dt_target_port=0;

static char g_default_netif[16] = "ETH_WAN";//"WIFI_STA_DEF";

static bool g_io_di_status[DEVICE_IO_DI_MAX]={1,1,1,1};
static bool g_io_do_status[DEVICE_IO_DO_MAX]={0,0,0,0};

/* Private function prototypes -----------------------------------------------*/

/* Private functions ---------------------------------------------------------*/

static void show_packet(int buflen, char* buf)
{	
    
	int j = buflen;
	int i;
	//printf("packet length :%d\n packet content : ",j);
	for(i = 0; i < j;i++)
	{
		printf("%02X ", (unsigned char)buf[i]);
	} 
}


 /****************************************************************************
 *
 * NAME: cb_report_state
 * params u16ClusterID cid, if is 0xFFFF will report all cid status.
 * return 0 success, else value fail.
 * DESCRIPTION:
 * Report plug status.
 *
 ****************************************************************************/
static int cb_report_state(char *cid)
{
	char *cids[] = {cid};
	return device_report_status(cids, 1);
}

 /****************************************************************************
 *
 * NAME: cb_report_state
 * params u16ClusterID cid, if is 0xFFFF will report all cid status.
 * return 0 success, else value fail.
 * DESCRIPTION:
 * Report plug status.
 *
 ****************************************************************************/
int device_report_status(char *cids[], int cids_num)
{

	// MDF_ERROR_CHECK(!mlink_get_value, MDF_FAIL, "this device does not support get_status");

#ifndef CONFIG_MQTT_ENABLE
	return MDF_OK;
#endif

	esp_err_t ret					  = MDF_OK;
	char *resp_data	        		  = NULL;
	int resp_size;
	char *characteristics_list		  = NULL;

	characteristic_value_t value	  = {0};

	for (int i = 0; i < cids_num; ++i) {
		char *tmp_str = NULL;

		switch (mlink_get_characteristics_format(cids[i])) {
			case CHARACTERISTIC_FORMAT_INT:
				ret = mlink_get_value(cids[i], &value.value_int);
				MDF_ERROR_BREAK(ret < 0, "<%s> mlink_get_value", esp_err_to_name(ret));
				mlink_json_pack(&tmp_str, "cid", cids[i]);
				mlink_json_pack(&tmp_str, "value", value.value_int);
				break;

			case CHARACTERISTIC_FORMAT_DOUBLE:
				ret = mlink_get_value(cids[i], &value.value_float);
				MDF_ERROR_BREAK(ret < 0, "<%s> mlink_get_value", esp_err_to_name(ret));
				mlink_json_pack(&tmp_str, "cid", cids[i]);
				mlink_json_pack_double(&tmp_str, "value", value.value_float);
				break;

			case CHARACTERISTIC_FORMAT_STRING:
				ret = mlink_get_value(cids[i], &value.value_string);
				MDF_ERROR_BREAK(ret < 0, "<%s> mlink_get_value", esp_err_to_name(ret));
				mlink_json_pack(&tmp_str, "cid", cids[i]);
				mlink_json_pack(&tmp_str, "value", value.value_string);
				break;

			default:
				MDF_LOGW("Data types in this format are not supported");
				break;

		}

		if (tmp_str) {
			mlink_json_pack(&characteristics_list, "[]", tmp_str);
			MDF_FREE(tmp_str);
		}
	}

	MDF_ERROR_GOTO(!characteristics_list, EXIT, "Create a json string");

	mlink_json_pack(&resp_data,
							 "characteristics", characteristics_list);
	MDF_FREE(characteristics_list);

	resp_size = mlink_json_pack(&resp_data, "type", "status_change");

	ret = mlink_mqtt_write(&resp_data, resp_size);
	MDF_ERROR_GOTO(ret != MDF_OK, EXIT, "Report message fail");
	
EXIT:
	MDF_FREE(resp_data);
	
	return MDF_OK;

}

void device_set_reboot_time(int time)
{
	if(g_reboot_time != time){
		g_reboot_time = time;
		mdf_info_save(DEVICE_REBOOT_TIME_STORE_KEY, &g_reboot_time, sizeof(g_reboot_time));
	}
}

int device_get_reboot_time()
{
	return g_reboot_time;
}

void device_set_report_time(int time)
{
	if(g_report_time != time){
		g_report_time = time;
		mdf_info_save(DEVICE_REPORT_TIME_STORE_KEY, &g_report_time, sizeof(g_report_time));
	}
}

int device_get_report_time()
{
	return g_report_time;
}

void device_set_mode(int mode)
{
	if(g_mode != mode){
		g_mode = mode;
		mdf_info_save(DEVICE_MODE_STORE_KEY, &g_mode, sizeof(g_mode));
	}
}

int device_get_mode()
{
	return g_mode;
}

void device_set_mesh_addr(uint8_t * addr)
{
	// if(memcmp(g_mesh_addr, addr, sizeof(g_mesh_addr)) != 0){
		memcpy(g_mesh_addr, addr, sizeof(g_mesh_addr));
		if(ESP_OK == mdf_info_save(DEVICE_MESH_ADDR_STORE_KEY, g_mesh_addr, sizeof(g_mesh_addr))){
			g_mesh_id_is_set = true;
		}
	// }
}

void device_get_mesh_addr(uint8_t * addr)
{
    if(g_mesh_id_is_set != true){
        uint8_t self_mac[6];
        if(ESP_OK == esp_wifi_get_mac(ESP_IF_WIFI_STA, self_mac)){
			memcpy(addr, self_mac, sizeof(self_mac));
		}
    }else{
		memcpy(addr, g_mesh_addr, sizeof(g_mesh_addr));
    }
	
}

void device_set_default_netif_name(char *netifkey)
{
	if(strcmp(g_default_netif, netifkey) != 0){
		strcpy(g_default_netif, netifkey);
		mdf_info_save(DEVICE_DEFAULT_NETIF_STORE_KEY, g_default_netif, sizeof(g_default_netif));
	}
}

char *device_get_default_netif_name(char *netifkey)
{
	if(netifkey){strcpy(netifkey, g_default_netif);}
	return g_default_netif;
}

void device_set_sn(char *sn)
{
	if(strcmp(g_device_sn, sn) != 0){
		strcpy(g_device_sn, sn);
		mdf_info_save(DEVICE_DEVICE_SN_STORE_KEY, g_device_sn, sizeof(g_device_sn));
	}
}

char *device_get_sn(char *sn)
{
	if(sn){strcpy(sn, g_device_sn);}
	return g_device_sn;
}

#if 0
/*
	设置wifi 关闭/开启
*/
void device_set_wifi_ap_disable(bool value)
{
	if(g_wifi_ap_cfg.disable != value ){
		g_wifi_ap_cfg.disable = value;
		mdf_info_save(DEVICE_SSID_PASSWORD_STORE_KEY, &g_wifi_ap_cfg, sizeof(g_wifi_ap_cfg));
	}
}

bool device_get_wifi_ap_disable()
{
	return g_wifi_ap_cfg.disable;
}

/*
	设置wifi ssid隐藏功能
*/
void device_set_wifi_ap_ssid_hide(bool value)
{
	if(g_wifi_ap_cfg.ssid_hide != value ){
		g_wifi_ap_cfg.ssid_hide = value;
		mdf_info_save(DEVICE_SSID_PASSWORD_STORE_KEY, &g_wifi_ap_cfg, sizeof(g_wifi_ap_cfg));
	}
}

bool device_get_wifi_ap_ssid_hide()
{
	return g_wifi_ap_cfg.ssid_hide;
}

void device_set_wifi_ap_ssid_password(const char *ssid, const char *password)
{
	bool save = false;
	if( ssid && strcmp(g_wifi_ap_cfg.ssid, ssid) != 0 ){
		strcpy(g_wifi_ap_cfg.ssid, ssid);
		save = true;
	}
	if( password && strcmp(g_wifi_ap_cfg.password, password) != 0){
		strcpy(g_wifi_ap_cfg.password, password);
		save = true;
	}
	if(save){
		mdf_info_save(DEVICE_SSID_PASSWORD_STORE_KEY, &g_wifi_ap_cfg, sizeof(g_wifi_ap_cfg));
	}
}

const char *device_get_wifi_ap_ssid(void)
{
	return g_wifi_ap_cfg.ssid;
}
const char *device_get_wifi_ap_password(void)
{
	return g_wifi_ap_cfg.password;
}

/*
	设置wifi信道
*/
void device_set_wifi_ap_channel(uint8_t value)
{
	if(g_wifi_channel != value){
		g_wifi_channel = value;
		mdf_info_save(DEVICE_WIFI_CHANNEL_STORE_KEY, &g_wifi_channel, sizeof(g_wifi_channel));
	}
}

uint8_t device_get_wifi_ap_channel()
{
	return g_wifi_channel;
}

void app_set_static_ip_enable(bool enable)
{
	if(g_static_ip_enable!=enable){
		g_static_ip_enable=enable;
		mdf_info_save(STATIC_IP_ENABLE_STORE_KEY, &g_static_ip_enable, sizeof(g_static_ip_enable));
	}
}

bool app_get_static_ip_enable()
{
	return g_static_ip_enable;
}

void app_set_static_ip_info(const char *ip, const char *netmask, const char *gw)
{
	if(ip){
		if(strcmp(g_static_ip, ip)!=0){
			strcpy(g_static_ip, ip);
			mdf_info_save(STATIC_IP_STORE_KEY, g_static_ip, sizeof(g_static_ip));
		}
	}
	if(netmask){
		if(strcmp(g_static_netmask, netmask)!=0){
			strcpy(g_static_netmask, netmask);
			mdf_info_save(STATIC_NETMASK_STORE_KEY, g_static_netmask, sizeof(g_static_netmask));
		}
	}
	if(gw){
		if(strcmp(g_static_gw, gw)!=0){
			strcpy(g_static_gw, gw);
			mdf_info_save(STATIC_GW_STORE_KEY, g_static_gw, sizeof(g_static_gw));
		}
	}

}

int app_get_static_ip_info(char *ip, char *netmask, char *gw)
{
	if(ip){
		strcpy(ip, g_static_ip);
	}
	if(netmask){
		strcpy(netmask, g_static_netmask);
	}
	if(gw){
		strcpy(gw, g_static_gw);
	}

	return 0;
}

const char *app_get_username()
{
	return "admin";
}

int app_set_user_password(char *passwd)
{
	if(strncmp(g_web_user_password, passwd, sizeof(g_web_user_password))!=0){
		strncpy(g_web_user_password, passwd, sizeof(g_web_user_password));
		mdf_info_save(WEB_USER_PASSWORD_STORE_KEY, g_web_user_password, sizeof(g_web_user_password));
	}
	return 0;
}

const char *app_get_user_password()
{
	return g_web_user_password;
}
#endif

int device_set_dt_target_ip(const char *value)
{
	strcpy(g_dt_target_ip, value);
	return 0;
}

const char * device_get_dt_target_ip()
{
	return g_dt_target_ip;
}

int device_set_dt_target_port(int value)
{
	g_dt_target_port = value;
	return 0;
}

int device_get_dt_target_port()
{
	return g_dt_target_port;
}

// void device_dlt645_set_password(const char *pass)
// {
// 	strncpy(g_dlt645_password, pass, 8);
// 	mdf_info_save(DEVICE_DLT645_PASS_STORE_KEY, g_dlt645_password, sizeof(g_dlt645_password));
// }
// char *device_dlt645_get_password(void)
// {
// 	return g_dlt645_password;
// }

/**
 * 返回电源状态
 * return int
 * 1：外部电源
 * 0：电池供电
 */
int device_get_power_source(void) {
	if(gpio_get_level(BOARD_IO_POWIN_DEC) == 1){
		return 1;
	}
	return 0;
}

/******************************** IO START *********************************/

int device_set_do_status(uint8_t index, int val)
{
	switch(index){
		case DEVICE_IO_DO01:
			iot_board_led_set_state(BOARD_IO_DO_1, val);
			break;
		case DEVICE_IO_DO02:
			iot_board_led_set_state(BOARD_IO_DO_2, val);
			break;
		case DEVICE_IO_DO03:
			iot_board_led_set_state(BOARD_IO_DO_3, val);
			break;
		case DEVICE_IO_DO04:
			iot_board_led_set_state(BOARD_IO_DO_4, val);
			break;
		default:
			ESP_LOGW(TAG, "device_set_do_status index error");
			return ESP_ERR_INVALID_ARG;
	}
	g_io_do_status[index] = val;
	return mdf_info_save(DEVICE_IO_DO_STATUS_STORE_KEY, g_io_do_status, sizeof(g_io_do_status));
}

int device_get_do_status(uint8_t index){
	return g_io_do_status[index];
	// int val = 0;
	// switch(index){
	// 	case DEVICE_IO_DO01:
	// 		val = iot_board_led_get_state(BOARD_IO_DO_1);
	// 		break;
	// 	case DEVICE_IO_DO02:
	// 		val = iot_board_led_get_state(BOARD_IO_DO_2);
	// 		break;
	// 	case DEVICE_IO_DO03:
	// 		val = iot_board_led_get_state(BOARD_IO_DO_3);
	// 		break;
	// 	case DEVICE_IO_DO04:
	// 		val = iot_board_led_get_state(BOARD_IO_DO_4);
	// 		break;
	// 	default:
	// 		return 0;
	// }
	// return val;
}

void device_set_di_status(uint8_t index, int val)
{
	g_io_di_status[index] = val;
}


int device_get_di_status(uint8_t index){
	return g_io_di_status[index];
}

/*
	返回AI电压 单位：mV
*/
esp_err_t device_get_ai_status(uint8_t index, float *out_val){
	// subdev_port_t *subdev = mlink_get_subdev_handle_by_index(0);
	switch(index){
		case DEVICE_IO_AI01:
			if(ESP_OK != driver_adc_get_voltage(DRIVER_ADC_CH_AI_1, out_val)){
				return ESP_FAIL;
			}
			break;
		case DEVICE_IO_AI02:
			if(ESP_OK != driver_adc_get_voltage(DRIVER_ADC_CH_AI_2, out_val)){
				return ESP_FAIL;
			}
			break;
		case DEVICE_IO_AI03:
			if(ESP_OK != driver_adc_get_voltage(DRIVER_ADC_CH_AI_3, out_val)){
				return ESP_FAIL;
			}
			break;
		case DEVICE_IO_AI_PT100:// DEVICE_IO_AI_PT100
			if(ESP_OK != driver_adc_get_voltage(DRIVER_ADC_CH_PT100, out_val)){
				return ESP_FAIL;
			}
			break;
		case DEVICE_IO_AI_BATTERY:
		case DEVICE_IO_AI_BATTERY_LEVEL:
			if(ESP_OK != driver_adc_get_voltage(DRIVER_ADC_CH_BAT, out_val)){
				return ESP_FAIL;
			}
			break;
		default:
			return ESP_ERR_INVALID_ARG;
	}
	return ESP_OK;
}


void device_set_temperature(float val)
{
	g_temperature = val;
}

float device_get_temperature()
{
	return g_temperature;
}

/**
 * 扫描IO状态，并写入缓存
 */
void subdev_io_scan_task(void *arg) {
	int index;
	subdev_port_t *subdev = mlink_get_subdev_handle_by_index(0);
	if(subdev == NULL){
		ESP_LOGI(TAG, "subdev_io_scan_task subdev is NULL");
		return;
	}
	time_t now = time(NULL);
	// ESP_LOGI(TAG, "subdev_io_scan_task start");
	// DI scan
	for(index = 0; index < DEVICE_IO_DI_MAX; index++){
		subdev_cid_t *cid_handle = NULL;
		switch(index){
			case DEVICE_IO_DI01:{
				static subdev_cid_t *cid_static = NULL;
				if(cid_static == NULL){
					cid_static = mlink_get_subdev_cid_handle_by_name(subdev, DEVICE_CID_DI01, NULL);
				}
				cid_handle = cid_static;
			}
				break;
			case DEVICE_IO_DI02:{
				static subdev_cid_t *cid_static = NULL;
				if(cid_static == NULL){
					cid_static = mlink_get_subdev_cid_handle_by_name(subdev, DEVICE_CID_DI02, NULL);
				}
				cid_handle = cid_static;
			}
				break;
			case DEVICE_IO_DI03:{
				static subdev_cid_t *cid_static = NULL;
				if(cid_static == NULL){
					cid_static = mlink_get_subdev_cid_handle_by_name(subdev, DEVICE_CID_DI03, NULL);
				}
				cid_handle = cid_static;
			}
				break;
			case DEVICE_IO_DI04:{
				static subdev_cid_t *cid_static = NULL;
				if(cid_static == NULL){
					cid_static = mlink_get_subdev_cid_handle_by_name(subdev, DEVICE_CID_DI04, NULL);
				}
				cid_handle = cid_static;
			}
				break;
			default:
				break;
		}
		int val_now = device_get_di_status(index);

		// 变换上报处理 周期上报处理
		if(mlink_subdev_compare_change_value(cid_handle, &val_now) || mlink_subdev_check_max_inr(cid_handle, now)){
			// report cid
			cid_handle->report_time = now;
			write_cid_to_report_queue(subdev, cid_handle, pdMS_TO_TICKS(100));
		}
		mlink_subdev_set_cache_value(cid_handle, &val_now);
		cid_handle->update_time = now;
		cid_handle->error = 0;
	}

	// DO scan
	for(index = 0; index < DEVICE_IO_DO_MAX; index++){
		subdev_cid_t *cid_handle = NULL;
		switch(index){
			case DEVICE_IO_DO01:{
				static subdev_cid_t *cid_static = NULL;
				if(cid_static == NULL){
					cid_static = mlink_get_subdev_cid_handle_by_name(subdev, DEVICE_CID_DO01, NULL);
				}
				cid_handle = cid_static;
			}
				break;
			case DEVICE_IO_DO02:{
				static subdev_cid_t *cid_static = NULL;
				if(cid_static == NULL){
					cid_static = mlink_get_subdev_cid_handle_by_name(subdev, DEVICE_CID_DO02, NULL);
				}
				cid_handle = cid_static;
			}
				break;
			case DEVICE_IO_DO03:{
				static subdev_cid_t *cid_static = NULL;
				if(cid_static == NULL){
					cid_static = mlink_get_subdev_cid_handle_by_name(subdev, DEVICE_CID_DO03, NULL);
				}
				cid_handle = cid_static;
			}
				break;
			case DEVICE_IO_DO04:{
				static subdev_cid_t *cid_static = NULL;
				if(cid_static == NULL){
					cid_static = mlink_get_subdev_cid_handle_by_name(subdev, DEVICE_CID_DO04, NULL);
				}
				cid_handle = cid_static;
			}
				break;
			default:
				break;
		}
		int32_t val_now = device_get_do_status(index);
		// int32_t val_pre = cid_handle->value.value_i32;
		// mlink_subdev_get_cache_value(cid_handle, &val_pre);
		// 变换上报处理
		// ESP_LOGI(TAG, "chage value %"PRIi32",%"PRIi32",%d, %.2f", val_pre, val_now, abs(val_pre - val_now), cid_handle->change_val);
		// if(cid_handle->change_val > 0){
		// 	if(abs(val_pre - val_now) >= cid_handle->change_val){
		// 		// report cid
		// 		cid_handle->report_time = now;
		// 		write_cid_to_report_queue(subdev, cid_handle, pdMS_TO_TICKS(100));
		// 	}
		// }
		// 变换上报处理 周期上报处理
		if(mlink_subdev_compare_change_value(cid_handle, &val_now) || mlink_subdev_check_max_inr(cid_handle, now)){
			// report cid
			cid_handle->report_time = now;
			write_cid_to_report_queue(subdev, cid_handle, pdMS_TO_TICKS(100));
		}

		mlink_subdev_set_cache_value(cid_handle, &val_now);
		cid_handle->update_time = now;
		cid_handle->error = 0;
	}

	// AI scan
	for(index = 0; index < DEVICE_IO_AI_MAX; index++){
		subdev_cid_t *cid_handle = NULL;
		switch(index){
			case DEVICE_IO_AI01:{
				static subdev_cid_t *cid_static = NULL;
				if(cid_static == NULL){
					cid_static = mlink_get_subdev_cid_handle_by_name(subdev, DEVICE_CID_AI01, NULL);
				}
				cid_handle = cid_static;
			}
				break;
			case DEVICE_IO_AI02:{
				static subdev_cid_t *cid_static = NULL;
				if(cid_static == NULL){
					cid_static = mlink_get_subdev_cid_handle_by_name(subdev, DEVICE_CID_AI02, NULL);
				}
				cid_handle = cid_static;
			}
				break;
			case DEVICE_IO_AI03:{
				static subdev_cid_t *cid_static = NULL;
				if(cid_static == NULL){
					cid_static = mlink_get_subdev_cid_handle_by_name(subdev, DEVICE_CID_AI03, NULL);
				}
				cid_handle = cid_static;
			}
				break;
			case DEVICE_IO_AI_PT100:{
				static subdev_cid_t *cid_static = NULL;
				if(cid_static == NULL){
					cid_static = mlink_get_subdev_cid_handle_by_name(subdev, DEVICE_CID_TEMPERATURE, NULL);
				}
				cid_handle = cid_static;
			}
				break;
			case DEVICE_IO_AI_BATTERY:{
				static subdev_cid_t *cid_static = NULL;
				if(cid_static == NULL){
					cid_static = mlink_get_subdev_cid_handle_by_name(subdev, DEVICE_CID_BAT_VOLTAGE, NULL);
				}
				cid_handle = cid_static;
			}
				break;
			case DEVICE_IO_AI_BATTERY_LEVEL:{
				static subdev_cid_t *cid_static = NULL;
				if(cid_static == NULL){
					cid_static = mlink_get_subdev_cid_handle_by_name(subdev, DEVICE_CID_BAT_LEVEL, NULL);
				}
				cid_handle = cid_static;
			}
				break;
			default:
				break;
		}
		float val_now=0;
		if(ESP_OK != device_get_ai_status(index, &val_now)){
			cid_handle->error = 1;
			continue;
		}
		switch(index){
			case DEVICE_IO_AI01:
			case DEVICE_IO_AI02:
			case DEVICE_IO_AI03:
				val_now = val_now*2.004/120;
				break;
			case DEVICE_IO_AI_PT100:// DEVICE_IO_AI_PT100
			{
				// 输入电压和参考电阻值
				float v_out = val_now/10.0/1000.0; // 测量到的电压 (V) 放大系数10

				// 计算PT100的电阻
				float r_pt100 = pt100_calculate_resistance(v_out);
				// ESP_LOGI(TAG, "PT100 电阻: %.2f 欧姆", r_pt100);

				// 计算温度
				val_now = pt100_calculate_temperature(r_pt100);
				// ESP_LOGI(TAG, "温度: %.2f °C", temperature);

				device_set_temperature(val_now);
			}
				break;
			case DEVICE_IO_AI_BATTERY:{
				val_now = val_now/0.180327868852459/1000.0;// 电池电压 放大系数2
				break;
			}
			case DEVICE_IO_AI_BATTERY_LEVEL:{
				val_now = val_now/0.180327868852459/1000.0;// 电池电压 放大系数2
				val_now = (val_now-3.7) / (4.2-3.7) * 100.0; // 电压转化为百分比
				if(val_now < 0){
					val_now = 0;
				}
				if(val_now > 100){
					val_now = 100;
				}
				// ESP_LOGD(TAG, "电池电压: %.2f %%", val_now);
				break;
			}
		}

		// 变换上报处理 周期上报处理
		if(mlink_subdev_compare_change_value(cid_handle, &val_now) || mlink_subdev_check_max_inr(cid_handle, now)){
			// report cid
			cid_handle->report_time = now;
			write_cid_to_report_queue(subdev, cid_handle, pdMS_TO_TICKS(100));
		}
		mlink_subdev_set_cache_value(cid_handle, &val_now);
		cid_handle->update_time = now;
		cid_handle->error = 0;
	}

	{
		int val_now = device_get_power_source();
		subdev_cid_t *cid_handle = mlink_get_subdev_cid_handle_by_name(subdev, DEVICE_CID_POWER_SOURCE, NULL);
		if(cid_handle) {
			// 变换上报处理 周期上报处理
			if(mlink_subdev_compare_change_value(cid_handle, &val_now) || mlink_subdev_check_max_inr(cid_handle, now)){
				// report cid
				cid_handle->report_time = now;
				write_cid_to_report_queue(subdev, cid_handle, pdMS_TO_TICKS(100));
			}
			mlink_subdev_set_cache_value(cid_handle, &val_now);
			cid_handle->update_time = now;
			cid_handle->error = 0;
		}
	}
}

/********************************* IO END ********************************/

esp_err_t device_dlt645_write_data(dlt645_t *p_dlt645, char *addr, char *pass_str, uint32_t ruler_id, float wirite_data)
{
	if(addr == NULL)
		return ESP_FAIL;

	int ret=ESP_OK;
	int length = 0;
	char buffer[64] = {0};
	char data[32] = {0};
	char in_data[16] = {0};
	uint8_t password[4];

	unsigned char ucCtrl = 0;
	S_D07_CTRL_CODE stCtrl = {0};
	S_D07_PACK_FRAME pack_frame = {0};
	F_D07_RULER_TRANS func = NULL;

	S_D07_RULER_INFO info = {0};
	ret = get_d07_ruler_info(ruler_id, &info);
	if(ret != E_D07_OK)	
	{
		ESP_LOGI(TAG, "不存在的规规约类型");
		return ESP_FAIL;
	}

	d07_str2bcd(pass_str, (uint8_t *)password, 4);
	data[0] = password[3]; // 不带安全认证密级为02H
	data[1] = password[2]; // 密码
	data[2] = password[1];
	data[3] = password[0];

	//data[0] = 0x02; // 不带安全认证密级为02H
	//data[1] = 0x0;data[2] = 0x0;data[3] = 0x0; // 密码
	data[4] = 0;data[5] = 0;data[6] = 0;data[7] = 0;//操作人员代码

	// 数据
	func = info.func;
	switch(info.format) {
		case E_D07_FMT_NN: {
			uint8_t nn_data = wirite_data;
			func(E_D07_TRANS_U2F,(char *)&nn_data, in_data);
		}
		case E_D07_FMT_NNNN:
		case E_D07_FMT_XXXX: {
			uint16_t nn_data = wirite_data;
			func(E_D07_TRANS_U2F,(char *)&nn_data, in_data);
		}
		case E_D07_FMT_NN_4:
		case E_D07_FMT_XXXXXX:
		case E_D07_FMT_XX_4: {
			uint32_t nn_data = wirite_data;
			func(E_D07_TRANS_U2F,(char *)&nn_data, in_data);
		}
		case E_D07_FMT_NN_6:
		case E_D07_FMT_XX_8: {
			uint64_t nn_data = wirite_data;
			func(E_D07_TRANS_U2F,(char *)&nn_data, in_data);
		}
		break;
		default:
			func(E_D07_TRANS_U2F,&wirite_data, in_data);
		break;
	}
	memcpy(&data[8], in_data, info.len);

	stCtrl.funcode = E_D07_CTRL_WRITE_DATA;
	stCtrl.direct = E_D07_CTRL_DIR_M2S;
	ret = trans_d07ctrl_struct2char(&ucCtrl, &stCtrl); //将结构封装成字节
	
	pack_frame.ctrl_code = ucCtrl;
	pack_frame.ruler_id = ruler_id;
	pack_frame.data_len = info.len + 4 + 8;
	pack_frame.data = data;
	memcpy(pack_frame.address,addr, 13 );
	ret = pack_d07_frame_by_data(&pack_frame, buffer, &length);
	
	ESP_LOGI(TAG," - frame:");
	show_packet(length, buffer);
	p_dlt645->sem_take(p_dlt645, portMAX_DELAY);
	p_dlt645->write(p_dlt645, (uint8_t *)buffer, length);
	/* 读响应 */
	length = p_dlt645->read(p_dlt645, (uint8_t *)buffer, sizeof(buffer));
	p_dlt645->sem_give(p_dlt645);
	if(length <= 0){
		return ESP_FAIL;
	}
	ESP_LOGI(TAG," - recv %d byte:", length);
	show_packet(length, (char *)buffer);

	S_D07_UNPACK stUnPack = {0};
	ret = unpack_d07_resp_frame(buffer, length, &stUnPack);
	if( E_D07_OK != ret || stUnPack.flag  != E_D07_UNPD_FLG_OK ){
		ESP_LOGE(TAG, "  解析出错! (error = %d : ", ret);
		return ESP_FAIL;
	}

	// 成功
	return ESP_OK;
}

esp_err_t device_dlt645_write_string(dlt645_t *p_dlt645, char *addr, char *pass_str, uint32_t ruler_id, char *wirite_data)
{
	if(addr == NULL)
		return ESP_FAIL;

	int ret=ESP_OK;
	int length = 0;
	char buffer[64] = {0};
	char data[32] = {0};
	char in_data[16] = {0};
	uint8_t password[4];

	unsigned char ucCtrl = 0;
	S_D07_CTRL_CODE stCtrl = {0};
	S_D07_PACK_FRAME pack_frame = {0};
	F_D07_RULER_TRANS func = NULL;

	S_D07_RULER_INFO info = {0};
	ret = get_d07_ruler_info(ruler_id, &info);
	if(ret != E_D07_OK)	
	{
		ESP_LOGI(TAG, "不存在的规规约类型");
		return ESP_FAIL;
	}	

	d07_str2bcd(pass_str, (uint8_t *)password, 4);
	data[0] = password[3]; // 不带安全认证密级为02H
	data[1] = password[2]; // 密码
	data[2] = password[1];
	data[3] = password[0];

	//data[0] = 0x02; // 不带安全认证密级为02H
	//data[1] = 0x0;data[2] = 0x0;data[3] = 0x0; // 密码
	data[4] = 0;data[5] = 0;data[6] = 0;data[7] = 0;//操作人员代码

	// 数据
	func = info.func;
	func(E_D07_TRANS_U2F,wirite_data, in_data);
	memcpy(&data[8], in_data, info.len);

	stCtrl.funcode = E_D07_CTRL_WRITE_DATA;
	stCtrl.direct = E_D07_CTRL_DIR_M2S;
	ret = trans_d07ctrl_struct2char(&ucCtrl, &stCtrl); //将结构封装成字节
	
	pack_frame.ctrl_code = ucCtrl;
	pack_frame.ruler_id = ruler_id;
	pack_frame.data_len = info.len + 4 + 8;
	pack_frame.data = data;
	memcpy(pack_frame.address,addr, 13 );
	ret = pack_d07_frame_by_data(&pack_frame, buffer, &length);
	
	// printf("\r\n - frame:");
	// show_packet(length, buffer);
	p_dlt645->sem_take(p_dlt645, portMAX_DELAY);
	p_dlt645->write(p_dlt645, (uint8_t *)buffer, length);
	/* 读响应 */
	length = p_dlt645->read(p_dlt645, (uint8_t *)buffer, sizeof(buffer));
	p_dlt645->sem_give(p_dlt645);
	if(length <= 0){
		return ESP_FAIL;
	}
	// printf("\r\n - recv %d byte:", length);
	// show_packet(length, (char *)buffer);

	S_D07_UNPACK stUnPack = {0};
	ret = unpack_d07_resp_frame(buffer, length, &stUnPack);
	if( E_D07_OK != ret || stUnPack.flag  != E_D07_UNPD_FLG_OK ){
		ESP_LOGE(TAG, "  解析出错! (error = %d : ", ret);
		return ESP_FAIL;
	}

	// 成功
	return ESP_OK;
}

esp_err_t device_dlt645_read_data(dlt645_t *p_dlt645, char *addr, uint32_t ruler_id, S_D07_UNPACK *stUnPack)
{
	if(addr == NULL || stUnPack == NULL)
		return ESP_FAIL;
	
	int ret=ESP_OK;
	int length = 0;
	char buffer[64] = {0};
	
	unsigned char ucCtrl = 0;
	S_D07_CTRL_CODE stCtrl = {0};
	S_D07_PACK_FRAME pack_frame = {0};
	
	stCtrl.direct = E_D07_CTRL_DIR_M2S;
	stCtrl.funcode = E_D07_CTRL_READ_DATA;
	ret = trans_d07ctrl_struct2char(&ucCtrl, &stCtrl); //将结构封装成字节
	
	pack_frame.ctrl_code = ucCtrl;
	pack_frame.ruler_id = ruler_id;
	pack_frame.data_len = 4;
	pack_frame.data = NULL;
	memcpy(pack_frame.address,addr, 13 );
	ret = pack_d07_frame_by_data(&pack_frame, buffer, &length);
	
	//ESP_LOGD(TAG," - frame:");
	//show_packet(length, buffer);
	p_dlt645->sem_take(p_dlt645, portMAX_DELAY);
	p_dlt645->write(p_dlt645, (uint8_t *)buffer, length);
	/* 读响应 */
	length = p_dlt645->read(p_dlt645, (uint8_t *)buffer, sizeof(buffer));
	p_dlt645->sem_give(p_dlt645);
	if(length <= 0){
		return ESP_FAIL;
	}
	//ESP_LOGD(TAG," - recv %d byte:", length);
	//show_packet(length, (char *)buffer);

	ret = unpack_d07_frame(buffer, length, stUnPack);
	if( E_D07_OK != ret || stUnPack->flag  != E_D07_UNPD_FLG_OK ){
		ESP_LOGE(TAG, "  解析出错! (error = %d : ", ret);
		return ESP_FAIL;
	}
	return ESP_OK;
}

esp_err_t device_dlt645_read_data_float(dlt645_t *p_dlt645, char *addr, uint32_t ruler_id, float *out_data)
{
	if(addr == NULL || out_data == NULL)
		return ESP_FAIL;
	
	int ret=ESP_OK;
	int length = 0;
	char buffer[64] = {0};
	
	unsigned char ucCtrl = 0;
	S_D07_CTRL_CODE stCtrl = {0};
	S_D07_PACK_FRAME pack_frame = {0};
	
	stCtrl.direct = E_D07_CTRL_DIR_M2S;
	stCtrl.funcode = E_D07_CTRL_READ_DATA;
	ret = trans_d07ctrl_struct2char(&ucCtrl, &stCtrl); //将结构封装成字节
	
	pack_frame.ctrl_code = ucCtrl;
	pack_frame.ruler_id = ruler_id;
	pack_frame.data_len = 4;
	pack_frame.data = NULL;
	memcpy(pack_frame.address,addr, 13 );
	ret = pack_d07_frame_by_data(&pack_frame, buffer, &length);
	
	//ESP_LOGD(TAG," - frame:");
	//show_packet(length, buffer);
	p_dlt645->sem_take(p_dlt645, portMAX_DELAY);
	p_dlt645->write(p_dlt645, (uint8_t *)buffer, length);
	/* 读响应 */
	length = p_dlt645->read(p_dlt645, (uint8_t *)buffer, sizeof(buffer));
	p_dlt645->sem_give(p_dlt645);
	if(length <= 0){
		return ESP_FAIL;
	}
	//ESP_LOGD(TAG," - recv %d byte:", length);
	//show_packet(length, (char *)buffer);

	S_D07_UNPACK stUnPack = {0};
	ret = unpack_d07_frame(buffer, length, &stUnPack);
	if( E_D07_OK != ret){
		ESP_LOGI(TAG, " resp (error = %d : ", ret);
		return ESP_FAIL;
	}
	// 成功 赋值
	switch(stUnPack.format) {
		case E_D07_FMT_NN: {
			*out_data = *((uint8_t *)&(stUnPack.data_unpack));
		}
		case E_D07_FMT_NNNN:
		case E_D07_FMT_XXXX: {
			*out_data = *((uint16_t *)&(stUnPack.data_unpack));
		}
		case E_D07_FMT_NN_4:
		case E_D07_FMT_XXXXXX:
		case E_D07_FMT_XX_4: {
			*out_data = *((uint32_t *)&(stUnPack.data_unpack));
		}
		// case E_D07_FMT_NN_6:
		// case E_D07_FMT_XX_8: {
		// 	*out_data = *((uint64_t *)&stUnPack.data_unpack);
		// }
		break;
		default:
			*out_data = stUnPack.data_unpack.fPower;
		break;
	}
	return ESP_OK;
}
esp_err_t device_dlt645_d97_write_data(dlt645_t *p_dlt645, char *addr, char *pass_str, uint32_t ruler_id, float wirite_data)
{
	// 判断输入参数的合法性
	if( p_dlt645 == NULL || addr == NULL || pass_str == NULL)
		return ESP_FAIL;
	
	int ret=ESP_OK;
	int length = 0;
	char buffer[64] = {0};
	char data[32] = {0};
	char in_data[16] = {0};

	unsigned char ucCtrl = 0;
	S_D97_CTRL_CODE stCtrl = {0};
	S_D97_PACK_FRAME pack_frame = {0};
	F_D97_RULER_TRANS func = NULL;

	S_D97_RULER_INFO info = {0};
	ret = get_d97_ruler_info(ruler_id, &info);
	if(ret != E_D07_OK)	
	{
		ESP_LOGI(TAG, "不存在的规规约类型");
		return ESP_FAIL;
	}
	uint8_t password[4];
	d07_str2bcd(pass_str, (uint8_t *)password, 4);
	data[0] = password[3]; // 不带安全认证密级为02H
	data[1] = password[2]; // 密码
	data[2] = password[1];
	data[3] = password[0];

	//data[0] = 0x01; // 不带安全认证密级为02H
	//data[1] = 0x11;data[2] = 0x11;data[3] = 0x11; // 密码

	// 数据
	func = info.func;
	switch(info.format) {
		case E_D97_FMT_NN: {
			uint8_t nn_data = wirite_data;
			func(E_D97_TRANS_U2F,(char *)&nn_data, in_data);
		}
		case E_D97_FMT_NNNN:
		case E_D97_FMT_XXXX: {
			uint16_t nn_data = wirite_data;
			func(E_D97_TRANS_U2F,(char *)&nn_data, in_data);
		}
		case E_D97_FMT_NN_4:
		case E_D97_FMT_XXXXXX:
		case E_D97_FMT_XX_4: {
			uint32_t nn_data = wirite_data;
			func(E_D97_TRANS_U2F,(char *)&nn_data, in_data);
		}
		case E_D97_FMT_NN_6:
		case E_D97_FMT_XX_8: {
			uint64_t nn_data = wirite_data;
			func(E_D97_TRANS_U2F,(char *)&nn_data, in_data);
		}
		break;
		default:
			func(E_D97_TRANS_U2F,&wirite_data, in_data);
		break;
	}
	memcpy(&data[4], in_data, info.len);
	
	stCtrl.direct = E_D97_CTRL_DIR_M2S;
	stCtrl.funcode = D97_CTRL_WRITE_DATA;
	ret = trans_d97ctrl_struct2char(&ucCtrl, &stCtrl); //将结构封装成字节
	
	pack_frame.ctrl_code = ucCtrl;
	pack_frame.ruler_id = ruler_id;
	pack_frame.data_len = 2+4+info.len;
	pack_frame.data = data;
	memcpy(pack_frame.address,addr, 13 );
	ret = pack_d97_frame_by_data(&pack_frame, buffer, &length);
	
	//ESP_LOGI(TAG," - frame:");
	//show_packet(length, buffer);
	p_dlt645->sem_take(p_dlt645, portMAX_DELAY);
	p_dlt645->write(p_dlt645, (uint8_t *)buffer, length);
	/* 读响应 */
	length = p_dlt645->read(p_dlt645, (uint8_t *)buffer, sizeof(buffer));
	p_dlt645->sem_give(p_dlt645);
	if(length <= 0){
		return ESP_FAIL;
	}
	//ESP_LOGI(TAG," - recv %d byte:", length);
	//show_packet(length, (char *)buffer);

	S_D97_UNPACK stUnPack = {0};
	ret = unpack_d97_resp_frame(buffer, length, &stUnPack);
	if( E_D97_OK != ret || stUnPack.flag  != E_D97_UNPD_FLG_OK ){
		ESP_LOGE(TAG, "  解析出错! (error = %d : ", ret);
		return ESP_FAIL;
	}

	// 成功
	return ESP_OK;
}

esp_err_t device_dlt645_d97_read_data(dlt645_t *p_dlt645, char *addr, uint32_t ruler_id, S_D97_UNPACK *stUnPack)
{
	if(addr == NULL || stUnPack == NULL)
		return ESP_FAIL;
	
	int ret=ESP_OK;
	int length = 0;
	char buffer[64] = {0};
	
	unsigned char ucCtrl = 0;
	S_D97_CTRL_CODE stCtrl = {0};
	S_D97_PACK_FRAME pack_frame = {0};
	
	stCtrl.direct = E_D97_CTRL_DIR_M2S;
	stCtrl.funcode = E_D97_CTRL_READ_DATA;
	ret = trans_d97ctrl_struct2char(&ucCtrl, &stCtrl); //将结构封装成字节
	
	pack_frame.ctrl_code = ucCtrl;
	pack_frame.ruler_id = ruler_id;
	pack_frame.data_len = 2;
	pack_frame.data = NULL;
	memcpy(pack_frame.address,addr, 13 );
	ret = pack_d97_frame_by_data(&pack_frame, buffer, &length);
	
	// ESP_LOGI(TAG," - frame:");
	// show_packet(length, buffer);
	p_dlt645->sem_take(p_dlt645, portMAX_DELAY);
	p_dlt645->write(p_dlt645, (uint8_t *)buffer, length);
	/* 读响应 */
	length = p_dlt645->read(p_dlt645, (uint8_t *)buffer, sizeof(buffer));
	p_dlt645->sem_give(p_dlt645);
	if(length <= 0){
		return ESP_FAIL;
	}
	// ESP_LOGI(TAG," - recv %d byte:", length);
	// show_packet(length, (char *)buffer);

	ret = unpack_d97_frame(buffer, length, stUnPack);
	if( E_D97_OK != ret){
		ESP_LOGE(TAG, " 解析出错! (error = %d : ", ret);
		return ESP_FAIL;
	}
	// 成功
	return ESP_OK;
}

esp_err_t device_dlt645_d97_read_float(dlt645_t *p_dlt645, char *addr, uint32_t ruler_id, float *out_data)
{
	int ret=ESP_OK;
	S_D97_UNPACK stUnPack;
	ret = device_dlt645_d97_read_data(p_dlt645, addr, ruler_id, &stUnPack);
	if( ESP_OK != ret){
		return ESP_FAIL;
	}
	// 成功
	switch(stUnPack.format) {
		case E_D97_FMT_NN: {
			*out_data = *((uint8_t *)&(stUnPack.data_unpack));
		}
		case E_D97_FMT_NNNN:
		case E_D97_FMT_XXXX: {
			*out_data = *((uint16_t *)&(stUnPack.data_unpack));
		}
		case E_D97_FMT_NN_4:
		case E_D97_FMT_XXXXXX:
		case E_D97_FMT_XX_4: {
			*out_data = *((uint32_t *)&(stUnPack.data_unpack));
		}
		// case E_D97_FMT_NN_6:
		// case E_D97_FMT_XX_8: {
		// 	*out_data = *((uint64_t *)&stUnPack.data_unpack);
		// }
		break;
		default:
			*out_data = stUnPack.data_unpack.fPower;
		break;
	}
	return ESP_OK;
}

/*
	设置dlt645设备通信速率
*/
esp_err_t device_dlt645_write_baudrate(dlt645_t *p_dlt645, char *addr, int value)
{
	if(addr == NULL)
		return ESP_FAIL;
	
	int ret=ESP_OK;
	int length = 0;
	char buffer[64] = {0};
	char data[32] = {0};
	
	unsigned char ucCtrl = 0;
	S_D07_CTRL_CODE stCtrl = {0};
	S_D07_PACK_FRAME pack_frame = {0};

	/* 
	通信速率字
	Bit7  Bit6     Bit5     Bit4    Bit3    Bit2   Bit1  Bit0
	保留 19200bps 9600bps 4800bps 2400bps 1200bps 600bps 保留
	*/
	switch(value){
		case 600:
			data[0] = BIT1;
		break;
		case 1200:
			data[0] = BIT2;
		break;
		case 2400:
			data[0] = BIT3;
		break;
		case 4800:
			data[0] = BIT4;
		break;
		case 9600:
			data[0] = BIT5;
		break;
		case 19200:
			data[0] = BIT6;
		break;

		default:
			return ESP_ERR_INVALID_ARG;
			break;
	}
	
	stCtrl.direct = E_D07_CTRL_DIR_M2S;
	stCtrl.funcode = D07_CTRL_MODIFY_BAUD;
	ret = trans_d07ctrl_struct2char(&ucCtrl, &stCtrl); //将结构封装成字节
	
	pack_frame.ctrl_code = ucCtrl;
	pack_frame.data_len = 1;
	pack_frame.data = data;
	memcpy(pack_frame.address,addr, 13 );
	ret = pack_d07_frame_for_ctrl_comm(&pack_frame, buffer, &length);
	
	//ESP_LOGD(TAG," - frame read addr:");
	//show_packet(length, buffer);
	p_dlt645->sem_take(p_dlt645, portMAX_DELAY);
	p_dlt645->write(p_dlt645, (uint8_t *)buffer, length);
	/* 读响应 */
	length = p_dlt645->read(p_dlt645, (uint8_t *)buffer, sizeof(buffer));
	p_dlt645->sem_give(p_dlt645);
	if(length <= 0){
		ESP_LOGE(TAG, "dlt645 not response");
		return ESP_FAIL;
	}
	//ESP_LOGD(TAG," - recv %d byte:", length);
	//show_packet(length, (char *)buffer);

	S_D07_UNPACK stUnPack = {0};
	ret = unpack_d07_resp_frame(buffer, length, &stUnPack);
	if( E_D07_OK != ret || stUnPack.flag  != E_D07_UNPD_FLG_OK ){
		ESP_LOGE(TAG, "  解析出错! (error = %d : ", ret);
		return ESP_FAIL;
	}
	if(data[0] != stUnPack.data_pack[0]){
		ESP_LOGE(TAG, "  返回错误!");
		return ESP_FAIL;
	}
	// 成功
	return ESP_OK;
}

/*
	dlt645清空电量命令
*/
esp_err_t device_dlt645_energy_reset(dlt645_t *p_dlt645, char *addr, char *pass_str)
{
	if(addr == NULL)
		return ESP_FAIL;
	
	int ret=ESP_OK;
	int length = 0;
	char buffer[64] = {0};
	char data[32] = {0};
	
	unsigned char ucCtrl = 0;
	S_D07_CTRL_CODE stCtrl = {0};
	S_D07_PACK_FRAME pack_frame = {0};
	//unsigned char password[4];
	
	uint8_t password[4];
	d07_str2bcd(pass_str, (uint8_t *)password, 4);
	data[0] = password[3]; // 不带安全认证密级为02H
	data[1] = password[2]; // 密码
	data[2] = password[1];
	data[3] = password[0];

	//data[0] = 0x00; // 不带安全认证密级为02H
	//data[1] = 0x0;data[2] = 0x0;data[3] = 0x0; // 密码
	data[4] = 0;data[5] = 0;data[6] = 0;data[7] = 0;//操作人员代码

	
	stCtrl.direct = E_D07_CTRL_DIR_M2S;
	stCtrl.funcode = D07_CTRL_CLEAR_METER;
	ret = trans_d07ctrl_struct2char(&ucCtrl, &stCtrl); //将结构封装成字节
	
	pack_frame.ctrl_code = ucCtrl;
	pack_frame.data_len = 8;
	pack_frame.data = data;
	memcpy(pack_frame.address,addr, 13 );
	ret = pack_d07_frame_for_ctrl_comm(&pack_frame, buffer, &length);
	
	//ESP_LOGD(TAG," - frame read addr:");
	//show_packet(length, buffer);
	p_dlt645->sem_take(p_dlt645, portMAX_DELAY);
	p_dlt645->write(p_dlt645, (uint8_t *)buffer, length);
	/* 读响应 */
	length = p_dlt645->read(p_dlt645, (uint8_t *)buffer, sizeof(buffer));
	p_dlt645->sem_give(p_dlt645);
	if(length <= 0){
		ESP_LOGE(TAG, "dlt645 not response");
		return ESP_FAIL;
	}
	//ESP_LOGD(TAG," - recv %d byte:", length);
	//show_packet(length, (char *)buffer);

	S_D07_UNPACK stUnPack = {0};
	ret = unpack_d07_resp_frame(buffer, length, &stUnPack);
	if( E_D07_OK != ret || stUnPack.flag  != E_D07_UNPD_FLG_OK ){
		ESP_LOGE(TAG, "  解析出错! (error = %d : ", ret);
		return ESP_FAIL;
	}
	// 成功
	return ESP_OK;
}

/*
	设置dlt645子设备地址
*/
esp_err_t device_dlt645_write_addr(dlt645_t *p_dlt645, char *addr)
{
	if(addr == NULL)
		return ESP_FAIL;
	
	int ret=ESP_OK;
	int length = 0;
	char buffer[64] = {0};
	char data[32] = {0};
	
	unsigned char ucCtrl = 0;
	S_D07_CTRL_CODE stCtrl = {0};
	S_D07_PACK_FRAME pack_frame = {0};

	// 地址
	d07_str2bcd(addr, (UINT8 *)data, 6);
	//ESP_LOGD(TAG," - set addr:");
	//show_packet(6, data);

	stCtrl.direct = E_D07_CTRL_DIR_M2S;
	stCtrl.funcode = E_D07_CTRL_WRITE_ADDR;
	ret = trans_d07ctrl_struct2char(&ucCtrl, &stCtrl); //将结构封装成字节
	
	pack_frame.ctrl_code = ucCtrl;
	pack_frame.data_len = 6;
	pack_frame.data = data;
	memcpy(pack_frame.address,"AAAAAAAAAAAA", 13 );
	ret = pack_d07_frame_for_ctrl_comm(&pack_frame, buffer, &length);
	
	//ESP_LOGD(TAG," - frame read addr:");
	//show_packet(length, buffer);
	p_dlt645->sem_take(p_dlt645, portMAX_DELAY);
	p_dlt645->write(p_dlt645, (uint8_t *)buffer, length);
	/* 读响应 */
	length = p_dlt645->read(p_dlt645, (uint8_t *)buffer, sizeof(buffer));
	p_dlt645->sem_give(p_dlt645);
	if(length <= 0){
		ESP_LOGE(TAG, "dlt645 not response");
		return ESP_FAIL;
	}
	//ESP_LOGD(TAG," - recv %d byte:", length);
	//show_packet(length, (char *)buffer);

	S_D07_UNPACK stUnPack = {0};
	ret = unpack_d07_resp_frame(buffer, length, &stUnPack);
	if( E_D07_OK != ret || stUnPack.flag  != E_D07_UNPD_FLG_OK ){
		ESP_LOGE(TAG, "  解析出错! (error = %d : ", ret);
		return ESP_FAIL;
	}
	// 成功
	return ESP_OK;
}

/*
	读dlt645设备地址 一对一连接的情况下可用
*/
esp_err_t device_dlt645_read_addr(dlt645_t *p_dlt645, char *addr)
{
	if(addr == NULL)
		return ESP_FAIL;
	
	int ret=ESP_OK;
	int length = 0;
	char buffer[64] = {0};
	
	unsigned char ucCtrl = 0;
	S_D07_CTRL_CODE stCtrl = {0};
	S_D07_PACK_FRAME pack_frame = {0};
	
	stCtrl.direct = E_D07_CTRL_DIR_M2S;
	stCtrl.funcode = E_D07_CTRL_READ_ADDR;
	ret = trans_d07ctrl_struct2char(&ucCtrl, &stCtrl); //将结构封装成字节
	
	pack_frame.ctrl_code = ucCtrl;
	pack_frame.data_len = 0;
	pack_frame.data = NULL;
	memcpy(pack_frame.address,"AAAAAAAAAAAA", 13);
	ret = pack_d07_frame_for_ctrl_comm(&pack_frame, buffer, &length);
	
	//ESP_LOGD(TAG," - frame read addr:");
	//show_packet(length, buffer);
	p_dlt645->sem_take(p_dlt645, portMAX_DELAY);
	p_dlt645->write(p_dlt645, (uint8_t *)buffer, length);
	/* 读响应 */
	length = p_dlt645->read(p_dlt645, (uint8_t *)buffer, sizeof(buffer));
	p_dlt645->sem_give(p_dlt645);
	if(length <= 0){
		ESP_LOGE(TAG, "dlt645 not response");
		return ESP_FAIL;
	}
	//ESP_LOGD(TAG," - recv %d byte:", length);
	//show_packet(length, (char *)buffer);

	S_D07_UNPACK stUnPack = {0};
	ret = unpack_d07_resp_frame(buffer, length, &stUnPack);
	if( E_D07_OK != ret || stUnPack.flag  != E_D07_UNPD_FLG_OK ){
		ESP_LOGE(TAG, "  解析出错! (error = %d : ", ret);
		return ESP_FAIL;
	}
	// 成功 赋值
	d07_bcd2str((const char *)stUnPack.data_pack, addr, 6);
	addr[12] = 0;
	ESP_LOGI(TAG,"dlt645 read addr: %s", addr);
	return ESP_OK;
}

/***************************  空开 操作函数       *********************************/

esp_err_t device_dlt645_set_onoff(dlt645_t *p_dlt645, char *addr, char *pass_str, int onoff)
{
	if(addr == NULL)
		return ESP_FAIL;

	if(g_mode == DEVICE_MODE_AIR_SWITCH_HPERFOR){
		return device_dlt645_hperfor_set_onoff(p_dlt645, addr, pass_str, onoff);
	}
	
	int ret=ESP_OK;
	int length = 0;
	char buffer[64] = {0};
	char data[64] = {0};
	
	unsigned char ucCtrl = 0;
	S_D07_CTRL_CODE stCtrl = {0};
	S_D07_PACK_FRAME pack_frame = {0};

	uint8_t password[4];
	d07_str2bcd(pass_str, (uint8_t *)password, 4);
	data[0] = password[3]; // 不带安全认证密级为02H
	data[1] = password[2]; // 密码
	data[2] = password[1];
	data[3] = password[0];
	//data[0] = 0x02; // 不带安全认证密级为02H
	//data[1] = 0x0;data[2] = 0x0;data[3] = 0x0; // 密码
	data[4] = 0;data[5] = 0;data[6] = 0;data[7] = 0;//操作人员代码
	// if(onoff){
	// 	data[8] = 0x1C; // 直接合闸 
	// }else{
	// 	data[8] = 0x1A; // 跳闸
	// }

	switch(onoff){
		case 0:
			data[8] = 0x1A; // 跳闸
		break;
		case 1:
			data[8] = 0x1C; // 直接合闸
		break;
		case 2:
			data[8] = 0x1B; // 合闸允许
		break;
		case 3:
			data[8] = 0x2A; // 报警
		break;
		case 4:
			data[8] = 0x2B; // 报警解除
		break;
		case 5:
			data[8] = 0x3A; // 保电
		break;
		case 6:
			data[8] = 0x3B; // 保电解除
		break;
		default:
			return MDF_FAIL;
			break;
	}
	data[9] = 0;
	
	time_t now;
	struct tm *tm_now;
	char datetime[32];
	time(&now);
	tm_now = localtime(&now)+10;
	snprintf(datetime, 128, "%02d%02d%02d%02d%02d%02d", 
			 tm_now->tm_sec, tm_now->tm_min, tm_now->tm_hour, tm_now->tm_mday, tm_now->tm_mon, tm_now->tm_year-100);
	d07_str2bcd(datetime, (uint8_t *)(&data[10]), 6);
	
	stCtrl.funcode = E_D07_CTRL_COMM;
	stCtrl.direct = E_D07_CTRL_DIR_M2S;
	ret = trans_d07ctrl_struct2char(&ucCtrl, &stCtrl); //将结构封装成字节
	if(ret != E_D07_OK){
		ESP_LOGE(TAG, "trans_d07ctrl_struct2char failed %d", ret);
		return ESP_FAIL;
	}
	
	pack_frame.data_len = 8 + 2 + 6;
	pack_frame.data = data;
	pack_frame.ctrl_code = ucCtrl;

	// DLT645 单播地址
	memcpy(pack_frame.address,addr, 13 );
	
	ret = pack_d07_frame_for_ctrl_comm(&pack_frame, buffer, &length);
	if(ret != E_D07_OK){
		ESP_LOGE(TAG, "pack frame failed %d", ret);
		return ESP_FAIL;
	}

	//ESP_LOGD(TAG," - frame:");
	//show_packet(length, buffer);
	p_dlt645->sem_take(p_dlt645, portMAX_DELAY);
	p_dlt645->write(p_dlt645, (uint8_t *)buffer, length);
	/* 读响应 */
	length = p_dlt645->read(p_dlt645, (uint8_t *)buffer, sizeof(buffer));
	p_dlt645->sem_give(p_dlt645);
	if(!(length > 0)){
		return ESP_FAIL;
	}

	//ESP_LOGD(TAG," - recv %d byte:", length);
	//show_packet(length, (char *)buffer);

	S_D07_UNPACK stUnPack = {0};
	ret = unpack_d07_resp_frame(buffer, length, &stUnPack);
	if( E_D07_OK != ret){
		ESP_LOGI(TAG, "response failed %d", ret);
		return ESP_FAIL;
	}

	return ESP_OK;
}

esp_err_t device_dlt645_get_onoff(dlt645_t *p_dlt645, char *addr, int *onoff)
{
	if(addr == NULL || onoff == NULL)
		return ESP_FAIL;
	
	int ret=ESP_OK;
	int length = 0;
	char buffer[64] = {0};
	
	unsigned char ucCtrl = 0;
	S_D07_CTRL_CODE stCtrl = {0};
	S_D07_PACK_FRAME pack_frame = {0};
	
	stCtrl.direct = E_D07_CTRL_DIR_M2S;
	stCtrl.funcode = E_D07_CTRL_READ_DATA;
	ret = trans_d07ctrl_struct2char(&ucCtrl, &stCtrl); //将结构封装成字节
	
	pack_frame.ctrl_code = ucCtrl;
	switch(g_mode){
		case DEVICE_MODE_AIR_SWITCH_HPERFOR:
			pack_frame.ruler_id = 0x02920000;
		break;

		case DEVICE_MODE_AIR_SWITCH_IMEGA:
			pack_frame.ruler_id = E_D07_IMEGA_RULER_TYPE_METER_RUN_STWD_1;
		break;

		default:
			pack_frame.ruler_id = E_D07_RULER_TYPE_METER_RUN_STWD_1;
		break;
	}
	
	pack_frame.data_len = 4;
	pack_frame.data = NULL;
	memcpy(pack_frame.address,addr, 13 );
	ret = pack_d07_frame_by_data(&pack_frame, buffer, &length);
	
	//ESP_LOGI(TAG," - frame:");
	//show_packet(length, buffer);
	p_dlt645->sem_take(p_dlt645, portMAX_DELAY);
	p_dlt645->write(p_dlt645, (uint8_t *)buffer, length);
	/* 读响应 */
	length = p_dlt645->read(p_dlt645, (uint8_t *)buffer, sizeof(buffer));
	p_dlt645->sem_give(p_dlt645);
	if(length <= 0){
		ESP_LOGI(TAG, "not data recv");
		return ESP_FAIL;
	}
	//ESP_LOGI(TAG," - recv %d byte:", length);
	//show_packet(length, (char *)buffer);

	S_D07_UNPACK stUnPack = {0};
	ret = unpack_d07_resp_frame(buffer, length, &stUnPack);
	if( E_D07_OK != ret ){
		ESP_LOGI(TAG, " get onoff resp (error = %d : ", ret);
		return ESP_FAIL;
	}
	// 成功 返回合闸状态
	switch(g_mode){
		case DEVICE_MODE_AIR_SWITCH_HPERFOR:
			if(stUnPack.data_pack[4] == 1){
				*onoff = 1; // 合闸
			}else{
				*onoff = 0; // 分闸
			}
		break;

		case DEVICE_MODE_AIR_SWITCH_IMEGA:
			if(stUnPack.data_pack[4] & BIT6){
				*onoff = 1; // 合闸
			}else{
				*onoff = 0; // 分闸
			}
		break;

		default:
			if(stUnPack.data_pack[4] & BIT6){
				*onoff = 0; // 分闸
			}else{
				*onoff = 1; // 合闸
			}
		break;
	}

	return ESP_OK;
}


esp_err_t device_dlt645_hperfor_set_onoff(dlt645_t *p_dlt645, char *addr, char *pass_str, int onoff)
{
	if(addr == NULL)
		return ESP_FAIL;
	
	int ret=ESP_OK;
	int length = 0;
	char buffer[64] = {0};
	char data[32] = {0};
	
	unsigned char ucCtrl = 0;
	S_D07_CTRL_CODE stCtrl = {0};
	S_D07_PACK_FRAME pack_frame = {0};

	uint8_t password[4];
	d07_str2bcd(pass_str, (uint8_t *)password, 4);
	data[0] = password[3]; // 不带安全认证密级为02H
	data[1] = password[2]; // 密码
	data[2] = password[1];
	data[3] = password[0];

	//data[0] = 0x00; // 不带安全认证密级为02H
	//data[1] = 0x0;data[2] = 0x0;data[3] = 0x0; // 密码
	data[4] = 0;data[5] = 0;data[6] = 0;data[7] = 0;//操作人员代码

	if(onoff){
		data[8] = 1; // 合闸
	}
	else {
		data[8] = 2; // 分闸
	}
	
	stCtrl.direct = E_D07_CTRL_DIR_M2S;
	stCtrl.funcode = D07_CTRL_COMM;
	ret = trans_d07ctrl_struct2char(&ucCtrl, &stCtrl); //将结构封装成字节
	
	pack_frame.ctrl_code = ucCtrl;
	pack_frame.ruler_id = 0x07000000;
	pack_frame.data_len = 4+8+1;
	pack_frame.data = data;
	memcpy(pack_frame.address,addr, 13 );
	ret = pack_d07_frame_by_data(&pack_frame, buffer, &length);
	
	//ESP_LOGI(TAG," - frame:");
	//show_packet(length, buffer);
	p_dlt645->sem_take(p_dlt645, portMAX_DELAY);
	p_dlt645->write(p_dlt645, (uint8_t *)buffer, length);
	/* 读响应 */
	length = p_dlt645->read(p_dlt645, (uint8_t *)buffer, sizeof(buffer));
	p_dlt645->sem_give(p_dlt645);
	if(length <= 0){
		return ESP_FAIL;
	}
	//ESP_LOGI(TAG," - recv %d byte:", length);
	//show_packet(length, (char *)buffer);

	S_D07_UNPACK stUnPack = {0};
	ret = unpack_d07_resp_frame(buffer, length, &stUnPack);
	if( E_D07_OK != ret || stUnPack.flag  != E_D07_UNPD_FLG_OK ){
		ESP_LOGE(TAG, "  解析出错! (error = %d : ", ret);
		return ESP_FAIL;
	}

	// 成功
	return ESP_OK;

}
esp_err_t device_cjt188_get_data(dlt645_t *p_dlt645, char *addr, uint32_t ruler_id, float *out_data)
{
	if(addr == NULL || out_data == NULL)
		return ESP_FAIL;
	
	int ret=ESP_OK;
	int length = 0;
	char buffer[64] = {0};
	
	unsigned char ucCtrl = 0;
	S_CJT188_CTRL_CODE stCtrl = {0};
	S_CJT188_PACK_FRAME pack_frame = {0};
	
	stCtrl.direct = E_CJT188_CTRL_DIR_M2S;
	stCtrl.funcode = E_CJT188_CTRL_READ_DATA;
	ret = trans_cjt188ctrl_struct2char(&ucCtrl, &stCtrl); //将结构封装成字节
	
	pack_frame.type = 0x10;
	pack_frame.ctrl_code = ucCtrl;
	pack_frame.ruler_id = ruler_id;
	pack_frame.data_len = 3;
	pack_frame.data = NULL;
	strcpy(pack_frame.address,addr);
	ret = pack_cjt188_frame_by_data(&pack_frame, buffer, &length);
	
	// ESP_LOGD(TAG," - frame:");
	// show_packet(length, buffer);
	p_dlt645->sem_take(p_dlt645, portMAX_DELAY);
	p_dlt645->write(p_dlt645, (uint8_t *)buffer, length);
	/* 读响应 */
	length = p_dlt645->read(p_dlt645, (uint8_t *)buffer, sizeof(buffer));
	p_dlt645->sem_give(p_dlt645);
	if(length <= 0){
		return ESP_FAIL;
	}
	// ESP_LOGD(TAG," - recv %d byte:", length);
	// show_packet(length, (char *)buffer);

	S_CJT188_UNPACK stUnPack = {0};
	ret = unpack_cjt188_frame(buffer, length, &stUnPack);
	if( E_CJT188_OK != ret){
		ESP_LOGI(TAG, " resp (error = %d : ", ret);
		return ESP_FAIL;
	}
	// 成功 赋值
	*out_data = stUnPack.data_unpack.fPower;
	return ESP_OK;
}

/* 空开数据轮询 */
void subdev_dlt645_scan_task(void *arg)
{
	int ret = ESP_OK;
	char cid_str_tmp[32];
	char *addr_str=NULL;
	char *data_id_str=NULL;
	uint32_t data_id;
	float read_data;
	dlt645_t *p_dlt645 = arg;
	// subdev_port_t *subdev = p_dlt645->port_data;

	while(1){
		for(int p=0;p<SUBDEV_PORT_MAX_NUM; p++){
			subdev_port_t *subdev = mlink_get_subdev_handle_by_index(p);
			if(subdev == NULL){
				vTaskDelay(pdMS_TO_TICKS(10));
				continue;
			}
			// 检查协议是否匹配
			if(!(subdev->protocol == SUBDEV_PROTOCOL_DLT645_07 || subdev->protocol == SUBDEV_PROTOCOL_DLT645_97 || subdev->protocol == SUBDEV_PROTOCOL_CJT188_04)){
				vTaskDelay(pdMS_TO_TICKS(10));
				continue;
			}
			// 检查串口号是否匹配
			if((subdev->info_union.serial.uart_num+1) !=  p_dlt645->uart_num){
				vTaskDelay(pdMS_TO_TICKS(10));
				continue;
			}
			if(subdev->cids_num == 0 ){
				vTaskDelay(pdMS_TO_TICKS(10));
				continue;
			}
		
			for(int i=0; i < subdev->cids_num; i++){
				subdev_cid_t *cid = &subdev->cids[i];

				switch(subdev->protocol){
					case SUBDEV_PROTOCOL_DLT645_07:
						strcpy(cid_str_tmp, cid->cid);
						addr_str = strtok(cid_str_tmp, "!");
						data_id_str = strtok(NULL, "!");
						if(addr_str == NULL || data_id_str == NULL){
							ESP_LOGI(TAG, "cid %s format error", cid->cid);
							goto CONTINUE;
						}
						// if (2 != sscanf(cid->cid, "%12s!%8s", addr_str, data_id_str)){
						// 	ESP_LOGE(TAG, "error %s", cid->cid);
						// 	goto CONTINUE;
						// }
						d07_str2bcd(data_id_str, (uint8_t *)&data_id, 4);
						ret = device_dlt645_read_data_float(p_dlt645, addr_str, data_id, &read_data);
						if(ret != ESP_OK){
							cid->error = 1;
							ESP_LOGE(TAG, "error %s", cid->cid);
							goto CONTINUE;
						}
						cid->error = 0;
						break;
					case SUBDEV_PROTOCOL_DLT645_97:
						strcpy(cid_str_tmp, cid->cid);
						addr_str = strtok(cid_str_tmp, "!");
						data_id_str = strtok(NULL, "!");
						if(addr_str == NULL || data_id_str == NULL){
							ESP_LOGI(TAG, "cid %s format error", cid->cid);
							goto CONTINUE;
						}
						// if (2 != sscanf(cid->cid, "%12s!%4s", addr_str, data_id_str)){
						// 	ESP_LOGE(TAG, "error %s", cid->cid);
						// 	goto CONTINUE;
						// }
						d97_str2bcd(data_id_str, (uint8_t *)&data_id, 2);
						ret = device_dlt645_d97_read_float(p_dlt645, addr_str, data_id, &read_data);
						if(ret != ESP_OK){
							cid->error = 1;
							ESP_LOGE(TAG, "error %s", cid->cid);
							goto CONTINUE;
						}
						cid->error = 0;
						break;
					case SUBDEV_PROTOCOL_CJT188_04:
						strcpy(cid_str_tmp, cid->cid);
						addr_str = strtok(cid_str_tmp, "!");
						data_id_str = strtok(NULL, "!");
						if(addr_str == NULL || data_id_str == NULL){
							ESP_LOGI(TAG, "cid %s format error", cid->cid);
							goto CONTINUE;
						}
						// if (2 != sscanf(cid->cid, "%14s!%4s", addr_str, data_id_str)){
						// 	ESP_LOGE(TAG, "error %s", cid->cid);
						// 	goto CONTINUE;
						// }
						cjt188_str2bcd(data_id_str, (uint8_t *)&data_id, 2);
						ret = device_cjt188_get_data(p_dlt645, addr_str, data_id, &read_data);
						if(ret != ESP_OK){
							cid->error = 1;
							ESP_LOGE(TAG, "error %s", cid->cid);
							goto CONTINUE;
						}
						cid->error = 0;
						break;

					default:
						break;
				}

				if(cid->f != 1.0){
					read_data = read_data * cid->f;
				}

				time_t now = time(NULL);
				float val_pre = cid->value.value_float;
				cid->value.value_float = read_data;
				cid->update_time = now;

				// 变换上报处理
				if(cid->change_val > 0){
					if(fabsf(val_pre - read_data) >= cid->change_val){
						// report cid
						cid->report_time = now;
						write_cid_to_report_queue(subdev, cid, pdMS_TO_TICKS(100));
					}
				}
				// 周期上报处理
				if(cid->max_inr > 0){
					if(now - cid->report_time >= cid->max_inr){
						cid->report_time = now;
						write_cid_to_report_queue(subdev, cid, pdMS_TO_TICKS(100));
					}
				}

				//ESP_LOGD(TAG, "T645 read %s %x:%f", ret==ESP_OK?"OK":"Fail",data_id, read_data);
	CONTINUE:
				vTaskDelay(pdMS_TO_TICKS(subdev->poll_interval+10)); // timeout between polls
			}
			mdf_event_loop_send(MDF_EVENT_MLINK_SET_STATUS, NULL);
			vTaskDelay(pdMS_TO_TICKS(10));
		}

	}
}

/**
 * @brief 子设备数据上报
 * */
// esp_err_t subdev_cid_report(int channel)
// {
// 	int ret = ESP_OK;
	
// 	char *characteristics_list		  = NULL;
// 	char *resp_data 				  = NULL;
// 	int resp_size;
// 	char *tmp_str = NULL;
// 	subdev_port_t *subdev = mlink_get_subdev_handle_by_index(channel);
// 	if(subdev == NULL){
// 		return ESP_FAIL;
// 	}
// 	ESP_LOGD(TAG, "cid num %d", subdev->cids_num);
// 	for(int i=0; i < subdev->cids_num; i++){
// 		subdev_cid_t *cid = &subdev->cids[i];

// 		tmp_str = NULL;
// 		mlink_json_pack(&tmp_str, "cid", cid->cid);
// 		switch(subdev->protocol){
// 			case SUBDEV_PROTOCOL_DLT645_07:
// 			case SUBDEV_PROTOCOL_DLT645_97:
// 			case SUBDEV_PROTOCOL_CJT188_04:
// 				mlink_json_pack_double(&tmp_str, "value", cid->value.value_float);
// 				if(cid->error != 0){
// 					mlink_json_pack(&tmp_str, "error", cid->error);
// 				}
// 				break;
// 			case SUBDEV_PROTOCOL_MODBUS_TCP:
// 			case SUBDEV_PROTOCOL_MODBUS_RTU:
// 			case SUBDEV_PROTOCOL_MODBUS_ASCII:
// 			case SUBDEV_PROTOCOL_MODBUS_UDP:
// 				if(strcmp(cid->type, "u16") == 0){
// 					mlink_json_pack(&tmp_str, "value", cid->value.value_u16);
// 				} else if(strcmp(cid->type, "u32") == 0){
// 					mlink_json_pack(&tmp_str, "value", cid->value.value_u32);
// 				}if(strcmp(cid->type, "i16") == 0){
// 					mlink_json_pack(&tmp_str, "value", cid->value.value_i16);
// 				} else if(strcmp(cid->type, "i32") == 0){
// 					mlink_json_pack(&tmp_str, "value", cid->value.value_i32);
// 				} else if(strcmp(cid->type, "float") == 0){
// 					mlink_json_pack_double(&tmp_str, "value", cid->value.value_float);
// 				}
// 				if(cid->error != 0){
// 					mlink_json_pack(&tmp_str, "error", cid->error);
// 				}
// 				break;
// 			default:
// 				break;
// 		}
// 		mlink_json_pack(&tmp_str, "update_time", cid->update_time);
// 		mlink_json_pack(&characteristics_list, "[]", tmp_str);
// 		MDF_FREE(tmp_str);
// 	}
// 	if(characteristics_list){
// 		switch(subdev->protocol){
// 			case SUBDEV_PROTOCOL_DLT645_07:
// 			case SUBDEV_PROTOCOL_DLT645_97:
// 			case SUBDEV_PROTOCOL_CJT188_04:
// 			case SUBDEV_PROTOCOL_MODBUS_RTU:
// 			case SUBDEV_PROTOCOL_MODBUS_ASCII:
// 				mlink_json_pack(&resp_data, "serial", subdev->info_union.serial.uart_num);
// 				break;
// 			case SUBDEV_PROTOCOL_MODBUS_TCP:
// 			case SUBDEV_PROTOCOL_MODBUS_UDP:{
// 				char *slave_ip=NULL;
// 				for(int i=0; i <subdev->info_union.modbus_tcp.slave_num; i++) {
// 					mlink_json_pack(&slave_ip, "[]", subdev->info_union.modbus_tcp.slave_ip[i]);
// 				}
// 				mlink_json_pack(&resp_data, "slave_ip", slave_ip);
// 				if(slave_ip)free(slave_ip);
// 				mlink_json_pack(&resp_data, "slave_port", subdev->info_union.modbus_tcp.slave_port);
// 				break;
// 			default:
// 				break;
// 			}
// 		}
// 		mlink_json_pack(&resp_data,"characteristics", characteristics_list);
// 		MDF_FREE(characteristics_list);
// 		resp_size = mlink_json_pack(&resp_data, "type", "status_change");
// 		ret = mlink_mqtt_write(&resp_data, resp_size);
// 		if(ret != MDF_OK)ESP_LOGE(TAG,"Report message fail");			
// 		MDF_FREE(resp_data);
// 	}

// 	return ret;
// }


/**
 * @brief 子设备cid数据上报
 * */
esp_err_t subdev_cid_value_report(subdev_port_t *subdev, subdev_cid_t *cid)
{
	int ret = ESP_OK;
	
	char *characteristics_list		  = NULL;
	char *resp_data 				  = NULL;
	int resp_size;
	char *tmp_str = NULL;

	tmp_str = NULL;
	mlink_json_pack(&tmp_str, "cid", cid->cid);

	subdev_json_pack_value(&tmp_str, cid->type, &cid->value);
	// if(strcmp(cid->type, "u16") == 0){
	// 	mlink_json_pack(&tmp_str, "value", cid->value.value_u16);
	// } else if(strcmp(cid->type, "u32") == 0){
	// 	mlink_json_pack(&tmp_str, "value", cid->value.value_u32);
	// }if(strcmp(cid->type, "i16") == 0){
	// 	mlink_json_pack(&tmp_str, "value", cid->value.value_i16);
	// } else if(strcmp(cid->type, "i32") == 0){
	// 	mlink_json_pack(&tmp_str, "value", cid->value.value_i32);
	// } else if(strcmp(cid->type, "float") == 0){
	// 	mlink_json_pack_double(&tmp_str, "value", cid->value.value_float);
	// }
	if(cid->error != 0){
		mlink_json_pack(&tmp_str, "error", cid->error);
	}

	char timestamp_str[32];
	sprintf(timestamp_str, "%lld", cid->update_time);
	mlink_json_pack(&tmp_str, "update_time", timestamp_str);
	mlink_json_pack(&characteristics_list, "[]", tmp_str);
	MDF_FREE(tmp_str);

	mlink_json_pack(&resp_data,"characteristics", characteristics_list);
	MDF_FREE(characteristics_list);

	char node[4];
	sprintf(node, "n%"PRIu8, subdev->port_index);
	mlink_json_pack(&resp_data,"node", node);
	resp_size = mlink_json_pack(&resp_data, "type", "status_change");
	ret = mlink_mqtt_write(&resp_data, resp_size);
	if(ret != MDF_OK)ESP_LOGE(TAG,"Report message fail");			
	MDF_FREE(resp_data);

	return ret;
}

static esp_err_t mlink_handle_subdev_get_data(mlink_handle_data_t *handle_data)
{
	esp_err_t ret	  = ESP_OK;
	char node[4];

	cid_value_t read_data;
	char **data_id_array=NULL;
	int data_id_num;
	char *data_str=NULL;
	int sync_flag = 0; // 同步读取标志

	ret = mlink_json_parse(handle_data->req_data, "node", node);
	MDF_ERROR_GOTO(ret != MDF_OK, EXIT, "Parse the json formatted string");
	uint8_t ch = atoi(&(node[1]));
	if(ch >= SUBDEV_PORT_MAX_NUM){
		ret = ESP_FAIL;
		return ret;
	}
	subdev_port_t *subdev = mlink_get_subdev_handle_by_index(ch);
	if(subdev == NULL){
		return ESP_FAIL;
	}

	mlink_json_parse(handle_data->req_data, "sync", &sync_flag);

	ret = mlink_json_parse(handle_data->req_data, "cids", &data_id_num);
	MDF_ERROR_GOTO(ret != MDF_OK, EXIT, "Parse the json formatted string");
	data_id_array = calloc(data_id_num, sizeof(char *));
	assert(data_id_array);

	ret = mlink_json_parse(handle_data->req_data, "cids", data_id_array);
	MDF_ERROR_GOTO(ret != MDF_OK, EXIT, "Parse the json formatted string");

	char cid_str_tmp[32];
	char *addr_str=NULL;
	char *data_id_str=NULL;
	uint32_t data_id;

    for (int i = 0; i < data_id_num; ++i) {
		char *cid_str = data_id_array[i];
		subdev_cid_t *cid_handle = mlink_get_subdev_cid_handle_by_name(subdev, cid_str, NULL);
		if(NULL == cid_handle) {
			MDF_LOGD("unkown cid: %s", cid_str);
			MDF_FREE(cid_str);
			continue;
		}
		// 读取数据，如果是同步请求，则直接读取，否则读取缓存数据
		// if(sync_flag == 1 || subdev->protocol == SUBDEV_PROTOCOL_NONE) {
		if(sync_flag == 1) {
			switch(subdev->protocol) {
				case SUBDEV_PROTOCOL_NONE:
					ret = mlink_get_value(cid_str, &read_data);
					break;
				case SUBDEV_PROTOCOL_DLT645_07:
					strcpy(cid_str_tmp, cid_str);
					addr_str = strtok(cid_str_tmp, "!");
					data_id_str = strtok(NULL, "!");
					if(addr_str == NULL || data_id_str == NULL){
						ESP_LOGI(TAG, "cid %s format error", cid_str);
						break;
					}
					// if (2 != sscanf(cids_item, "%12s!%8s", addr_str, data_id_str)){
					// 	ESP_LOGE(TAG, "error %s", cids_item);
					// 	break;
					// }
					d07_str2bcd(data_id_str, (uint8_t *)&data_id, 4);
					ret = device_dlt645_read_data_float(subdev->port_data, addr_str, data_id, &read_data);
					if(ret != ESP_OK){
						ESP_LOGE(TAG, "error %s", cid_str);
					}
					break;
				case SUBDEV_PROTOCOL_DLT645_97:
					strcpy(cid_str_tmp, cid_str);
					addr_str = strtok(cid_str_tmp, "!");
					data_id_str = strtok(NULL, "!");
					if(addr_str == NULL || data_id_str == NULL) {
						ESP_LOGI(TAG, "cid %s format error", cid_str);
						break;
					}
					// if (2 != sscanf(cids_item, "%12s!%4s", addr_str, data_id_str)){
					// 	ESP_LOGE(TAG, "error %s", cids_item);
					// 	break;
					// }
					d97_str2bcd(data_id_str, (uint8_t *)&data_id, 2);
					ret = device_dlt645_d97_read_float(subdev->port_data, addr_str, data_id, &read_data);
					if(ret != ESP_OK){
						ESP_LOGE(TAG, "error %s", cid_str);
					}
					break;
				case SUBDEV_PROTOCOL_CJT188_04:
					strcpy(cid_str_tmp, cid_str);
					addr_str = strtok(cid_str_tmp, "!");
					data_id_str = strtok(NULL, "!");
					if(addr_str == NULL || data_id_str == NULL){
						ESP_LOGI(TAG, "cid %s format error", cid_str);
						break;
					}
					// if (2 != sscanf(cids_item, "%14s!%4s", addr_str, data_id_str)){
					// 	ESP_LOGE(TAG, "error %s", cids_item);
					// 	break;
					// }
					cjt188_str2bcd(data_id_str, (uint8_t *)&data_id, 2);
					ret = device_cjt188_get_data(subdev->port_data, addr_str, data_id, &read_data);
					if(ret != ESP_OK){
						ESP_LOGE(TAG, "error %s", cid_str);
					}
					break;

				case SUBDEV_PROTOCOL_MODBUS_RTU:
				case SUBDEV_PROTOCOL_MODBUS_TCP:
				case SUBDEV_PROTOCOL_MODBUS_ASCII:
				case SUBDEV_PROTOCOL_MODBUS_UDP:
				{
					read_data = cid_handle->value;
				}
				break;
				default:
					ret = ESP_FAIL;
					break;
			}
		} else {
			read_data = cid_handle->value;
			ret = ESP_OK;
		}

		char *item=NULL;
		mlink_json_pack(&item, "cid", cid_str);
		if(ESP_OK == ret){
			subdev_json_pack_value(&item, cid_handle->type, &read_data);
			// if(strcmp(cid_handle->type, "u16") == 0){
			// 	mlink_json_pack(&item, "value", read_data.value_u16);
			// } else if(strcmp(cid_handle->type, "u32") == 0){
			// 	mlink_json_pack(&item, "value", read_data.value_u32);
			// } else if(strcmp(cid_handle->type, "i16") == 0){
			// 	mlink_json_pack(&item, "value", read_data.value_i16);
			// } else if(strcmp(cid_handle->type, "i32") == 0){
			// 	mlink_json_pack(&item, "value", read_data.value_i32);
			// } else if(strcmp(cid_handle->type, "float") == 0){
			// 	mlink_json_pack_double(&item, "value", read_data.value_float);
			// }
		}
		if(cid_handle->error != 0){
			mlink_json_pack(&item, "error", cid_handle->error);
		}
		mlink_json_pack(&data_str, "[]", item);
		MDF_FREE(item);

		MDF_FREE(cid_str);
    }
	mlink_json_pack(&handle_data->resp_data, "node", node);
	if(data_str)
		mlink_json_pack(&handle_data->resp_data, "data", data_str);
	MDF_FREE(data_str);

	EXIT:
	MDF_FREE(data_id_array);
	handle_data->resp_size = (handle_data->resp_data == NULL) ? 0 : strlen(handle_data->resp_data);

    return ret;
}

static esp_err_t mlink_handle_subdev_set_data(mlink_handle_data_t *handle_data)
{
	esp_err_t ret	  = ESP_OK;
	char node[4];
	char pass_str[10]="02000000";
	// float write_data;
	char **data_id_array=NULL;
	int data_id_num;

	ret = mlink_json_parse(handle_data->req_data, "node", node);
	MDF_ERROR_GOTO(ret != MDF_OK, EXIT, "Parse the json formatted string");
	uint8_t index = atoi(&(node[1]));
	if(index >= SUBDEV_PORT_MAX_NUM){
		ret = ESP_FAIL;
		return ret;
	}
	subdev_port_t *subdev = mlink_get_subdev_handle_by_index(index);
	if(subdev == NULL){
		return ESP_FAIL;
	}

	ret = mlink_json_parse(handle_data->req_data, "cids", &data_id_num);
	MDF_ERROR_GOTO(ret != MDF_OK, EXIT, "Parse the json formatted string");

	data_id_array = calloc(data_id_num, sizeof(char *));
	assert(data_id_array);

	ret = mlink_json_parse(handle_data->req_data, "cids", data_id_array);
	MDF_ERROR_GOTO(ret != MDF_OK, EXIT, "Parse the json formatted string");

	char cid_str[32];
	char addr_str[24];
	char data_id_str[9];
	uint32_t data_id;
	// subdev_cid_t cid;
	int cid_index;

    for (int i = 0; i < data_id_num; ++i) {

		char *value_item = data_id_array[i];
		ret = mlink_json_parse(value_item, "cid", cid_str);
		MDF_ERROR_GOTO(ret != MDF_OK,CONTINUE,"Parse the json formatted string");
	
		subdev_cid_t *cid_handle = mlink_get_subdev_cid_handle_by_name(subdev, cid_str, &cid_index);
		MDF_ERROR_GOTO(cid_handle == NULL,CONTINUE,"cid_handle is NULL");

		cid_value_t new_value;
		if(ESP_OK != subdev_json_parse_value(value_item, cid_handle->type, &new_value)){
			goto CONTINUE;
		}

		switch(subdev->protocol){
			case SUBDEV_PROTOCOL_NONE:{
				ret = mlink_set_value(cid_str, &new_value);
			}
				break;
			case SUBDEV_PROTOCOL_DLT645_07:
				mlink_json_parse(handle_data->req_data, "password", pass_str);
				if (2 != sscanf(cid_str, "%12s!%8s", addr_str, data_id_str)){
					ESP_LOGE(TAG, "error %s", cid_str);
					ret = ESP_FAIL;
					break;
				}

				d07_str2bcd(data_id_str, (uint8_t *)&data_id, 4);
				ret = device_dlt645_write_data(subdev->port_data, addr_str, pass_str, data_id, new_value.value_float);
				if(ret != ESP_OK){
					ESP_LOGE(TAG, "error %s", cid_str);
					ret = ESP_FAIL;
				}
				break;
			case SUBDEV_PROTOCOL_DLT645_97:
				mlink_json_parse(handle_data->req_data, "password", pass_str);
				if (2 != sscanf(cid_str, "%12s!%4s", addr_str, data_id_str)){
					ESP_LOGE(TAG, "error %s", cid_str);
					ret = ESP_FAIL;
					break;
				}

				d97_str2bcd(data_id_str, (uint8_t *)&data_id, 2);
				ret = device_dlt645_d97_write_data(subdev->port_data, addr_str, pass_str, data_id, new_value.value_float);
				if(ret != ESP_OK){
					ESP_LOGE(TAG, "error %s", cid_str);
					ret = ESP_FAIL;
				}
				break;
			case SUBDEV_PROTOCOL_MODBUS_RTU:
			case SUBDEV_PROTOCOL_MODBUS_TCP:
			case SUBDEV_PROTOCOL_MODBUS_ASCII:
			case SUBDEV_PROTOCOL_MODBUS_UDP:
			{
				mb_write_msg_t msg;
				msg.cid = cid_index;
				msg.val = new_value;
				ret = mb_app_write(subdev->port_data, &msg);
				break;
			}
			default:
			break;
		}

CONTINUE:
		MDF_FREE(value_item);
    }

	EXIT:
	MDF_FREE(data_id_array);
    return ret;
}


/*
	根据uart_num在g_subdev_port中找到协议是DLT645_07或DLT645_97或CJT188_04的port
	判断port->info_union.serial.uart_num是否等于要查找的值，如果是，则返回该指针
	如果不是，则继续查找下一个port，直到找到或遍历完所有port
*/
static dlt645_t* find_dlt645_port(int uart_num)
{
	for(int i=0; i<SUBDEV_PORT_MAX_NUM; i++){
		subdev_port_t *subdev = mlink_get_subdev_handle_by_index(i);
		if(subdev == NULL){
			continue;
		}
		if(subdev->protocol == SUBDEV_PROTOCOL_DLT645_07 || subdev->protocol == SUBDEV_PROTOCOL_DLT645_97 || subdev->protocol == SUBDEV_PROTOCOL_CJT188_04){
			if(subdev->info_union.serial.uart_num == uart_num){
				return (dlt645_t*)subdev->port_data;
			}
		}
	}
	return NULL;
}

static esp_err_t mlink_handle_dtl645_set_params(mlink_handle_data_t *handle_data)
{
	esp_err_t ret	  = ESP_OK;
	char addr[32];
	char subcmd[16];
	char pass_str[10];
	// char node[4];
	int serial;

	ret = mlink_json_parse(handle_data->req_data, "serial", &serial);
	MDF_ERROR_CHECK(ret != MDF_OK, MDF_FAIL, "Parse the json formatted string");
	dlt645_t *dlt645_handle = find_dlt645_port(serial);
	if(dlt645_handle == NULL){
		return ESP_FAIL;
	}

	ret = mlink_json_parse(handle_data->req_data, "addr", addr);
	if(ret != MDF_OK) {
		strcpy(addr, "AAAAAAAAAAAA");
	}

	ret = mlink_json_parse(handle_data->req_data, "password", pass_str);
	if(ret != MDF_OK){
		strcpy(pass_str, "02000000");
	}

	ret = mlink_json_parse(handle_data->req_data, "subcmd", subcmd);
	MDF_ERROR_CHECK(ret != MDF_OK, MDF_FAIL, "Parse the json formatted string");
	if(strcmp(subcmd, "set_addr") == 0) {
		char value[32];
		ret = mlink_json_parse(handle_data->req_data, "value", value);
		MDF_ERROR_CHECK(ret != MDF_OK, MDF_FAIL, "Parse the json formatted string");

		ret = device_dlt645_write_addr(dlt645_handle, value);
	}
	else if(strcmp(subcmd, "get_addr") == 0) {
		char value[32]={0};
		ret = device_dlt645_read_addr(dlt645_handle, value);
		handle_data->resp_size = mlink_json_pack(&handle_data->resp_data, "value", value);

	}
	else if(strcmp(subcmd, "set_baudrate") == 0) {
		
		int value;
		ret = mlink_json_parse(handle_data->req_data, "value", &value);
		MDF_ERROR_CHECK(ret != MDF_OK, MDF_FAIL, "Parse the json formatted string");

		ret = device_dlt645_write_baudrate(dlt645_handle, addr, value);

	}
	else if(strcmp(subcmd, "reset") == 0) {
		ret = device_dlt645_energy_reset(dlt645_handle, addr, pass_str);

	}
	else if(strcmp(subcmd, "set_onoff") == 0) {

		int value;
		ret = mlink_json_parse(handle_data->req_data, "value", &value);
		MDF_ERROR_CHECK(ret != MDF_OK, MDF_FAIL, "Parse the json formatted string");
		
		int subtype = 0;
		ret = mlink_json_parse(handle_data->req_data, "subtype", &subtype);
		if(ret == ESP_OK && subtype > 0) {
			if(subtype == 1) {
				ret = device_dlt645_hperfor_set_onoff(dlt645_handle, addr, pass_str, value);
			}
		} else {
			ret = device_dlt645_set_onoff(dlt645_handle, addr, pass_str, value);

		}
	}
	else if(strcmp(subcmd, "set_data") == 0) {

		uint32_t data_id;
		char data_id_str[9];
		ret = mlink_json_parse(handle_data->req_data, "id", data_id_str);
		MDF_ERROR_CHECK(ret != MDF_OK, MDF_FAIL, "Parse the json formatted string");
		
		char value[32];
		ret = mlink_json_parse(handle_data->req_data, "value", value);
		MDF_ERROR_CHECK(ret != MDF_OK, MDF_FAIL, "Parse the json formatted string");
		ESP_LOGI(TAG, "value: %s", value);
		d07_str2bcd(data_id_str, (uint8_t *)&data_id, 4);
		ret = device_dlt645_write_string(dlt645_handle, addr, pass_str, data_id, value);
	}
	else if(strcmp(subcmd, "get_data") == 0) {

		uint32_t data_id;
		char data_id_str[9];
		ret = mlink_json_parse(handle_data->req_data, "id", data_id_str);
		MDF_ERROR_CHECK(ret != MDF_OK, MDF_FAIL, "Parse the json formatted string");
		
		char value[32];
		d07_str2bcd(data_id_str, (uint8_t *)&data_id, 4);
		S_D07_UNPACK stUnPack;
		memset(&stUnPack, 0, sizeof(S_D07_UNPACK));
		ret = device_dlt645_read_data(dlt645_handle, addr, data_id, &stUnPack);
		MDF_ERROR_CHECK(ret != MDF_OK, MDF_FAIL, "Parse the json formatted string");
		// sprintf(value, "%X", *((unsigned int *)&stUnPack.data_unpack));
		handle_data->resp_size = mlink_json_pack(&handle_data->resp_data, "value", (char *)&stUnPack.data_unpack);
	}
	else if(strcmp(subcmd, "get_onoff") == 0) {


	} else {
		ret = ESP_FAIL;
	}

    return ret;
}

void device_load_record(void)
{
	mdf_info_load(DEVICE_REBOOT_TIME_STORE_KEY, &g_reboot_time, sizeof(g_reboot_time));
	mdf_info_load(DEVICE_MODE_STORE_KEY, &g_mode, sizeof(g_mode));
	if(ESP_OK == mdf_info_load(DEVICE_MESH_ADDR_STORE_KEY, g_mesh_addr, sizeof(g_mesh_addr))){
		g_mesh_id_is_set = true;
	}
	// mdf_info_load(STATIC_IP_STORE_KEY, g_static_ip, sizeof(g_static_ip));
	// mdf_info_load(STATIC_NETMASK_STORE_KEY, g_static_netmask, sizeof(g_static_netmask));
	// mdf_info_load(STATIC_GW_STORE_KEY, g_static_gw, sizeof(g_static_gw));
	// mdf_info_load(STATIC_IP_ENABLE_STORE_KEY, &g_static_ip_enable, sizeof(g_static_ip_enable));
	// mdf_info_load(WEB_USER_PASSWORD_STORE_KEY, g_web_user_password, sizeof(g_web_user_password));
	// mdf_info_load(DEVICE_WIFI_CHANNEL_STORE_KEY, &g_wifi_channel, sizeof(g_wifi_channel));
	// mdf_info_load(DEVICE_SSID_PASSWORD_STORE_KEY, &g_wifi_ap_cfg, sizeof(g_wifi_ap_cfg));
	// mdf_info_load(DEVICE_DLT645_PASS_STORE_KEY, g_dlt645_password, sizeof(g_dlt645_password));
	mdf_info_load(DEVICE_DEFAULT_NETIF_STORE_KEY, g_default_netif, sizeof(g_default_netif));
	mdf_info_load(DEVICE_DEVICE_SN_STORE_KEY, g_device_sn, sizeof(g_device_sn));
	mdf_info_load(DEVICE_IO_DO_STATUS_STORE_KEY, g_io_do_status, sizeof(g_io_do_status));
}

esp_err_t device_controller_init(void) 
{
	char name[32]					= {0};
	uint8_t sta_mac[6]				= {0};
	esp_err_t ret = MDF_OK;

    /**
     * @brief Configure MLink (LAN communication module)
     *          1.add device
     *          2.add characteristic of device
     *          3.add characteristic handle for get/set value of characteristic.
     */
    MDF_ERROR_ASSERT(esp_wifi_get_mac(ESP_IF_WIFI_STA, sta_mac));
    snprintf(name, sizeof(name), DEVICE_NAME "_%02x%02x", sta_mac[4], sta_mac[5]);

    MDF_ERROR_ASSERT(mlink_add_device(DEVICE_TID, name, CONFIG_APP_VERSION));
    MDF_ERROR_ASSERT(mlink_add_characteristic(DEVICE_CID_TID, "tid", CHARACTERISTIC_FORMAT_INT, CHARACTERISTIC_PERMS_READ, 0, 0, 1));
    MDF_ERROR_ASSERT(mlink_add_characteristic(DEVICE_CID_MODE, "mode", CHARACTERISTIC_FORMAT_INT, CHARACTERISTIC_PERMS_RW, 0, 0, 1));
	MDF_ERROR_ASSERT(mlink_add_characteristic(DEVICE_CID_REBOOT_TIME, "reboot_time", CHARACTERISTIC_FORMAT_INT, CHARACTERISTIC_PERMS_RW, 0, 0, 1));
	MDF_ERROR_ASSERT(mlink_add_characteristic(DEVICE_CID_REPORT_PERIOD, "report_period", CHARACTERISTIC_FORMAT_INT, CHARACTERISTIC_PERMS_RW, 0, 0, 1));

	MDF_ERROR_ASSERT(mlink_add_characteristic_handle(mlink_get_value, mlink_set_value));

	mlink_set_handle("subdev_get_data", mlink_handle_subdev_get_data);
	mlink_set_handle("subdev_set_data", mlink_handle_subdev_set_data);
	mlink_set_handle("dtl645_set_params", mlink_handle_dtl645_set_params);

	// 同步DO状态
	// for(int i=0; i<DEVICE_IO_DO_MAX; i++){
	// 	device_set_do_status(i, g_io_do_status[i]);
	// }
	
	return ret;
}

// const char *subdev_default_cids = "{\"request\":\"subdev_set_cids\",\"node\":\"n0\",\"poll_interval\":10,\"cids\":[{\"cid\":\"do01\",\"f\":1,\"type\":\"i32\",\"max_inr\":60,\"change_val\":1},{\"cid\":\"do02\",\"f\":1,\"type\":\"i32\",\"max_inr\":60,\"change_val\":1},{\"cid\":\"do03\",\"f\":1,\"type\":\"i32\",\"max_inr\":60,\"change_val\":1},{\"cid\":\"do04\",\"f\":1,\"type\":\"i32\",\"max_inr\":60,\"change_val\":1},{\"cid\":\"di01\",\"f\":1,\"type\":\"i32\",\"max_inr\":60,\"change_val\":1},{\"cid\":\"di02\",\"f\":1,\"type\":\"i32\",\"max_inr\":60,\"change_val\":1},{\"cid\":\"di03\",\"f\":1,\"type\":\"i32\",\"max_inr\":60,\"change_val\":1},{\"cid\":\"di04\",\"f\":1,\"type\":\"i32\",\"max_inr\":60,\"change_val\":1},{\"cid\":\"ai01\",\"f\":1,\"type\":\"float\",\"max_inr\":60,\"change_val\":1},{\"cid\":\"ai02\",\"f\":1,\"type\":\"float\",\"max_inr\":60,\"change_val\":1},{\"cid\":\"ai03\",\"f\":1,\"type\":\"float\",\"max_inr\":60,\"change_val\":1},{\"cid\":\"ai04\",\"f\":1,\"type\":\"float\",\"max_inr\":60,\"change_val\":0},{\"cid\":\"32\",\"f\":1,\"type\":\"float\",\"max_inr\":60,\"change_val\":1}]}";

#if 1
esp_err_t device_subdev_0_init(void) 
{
	esp_err_t ret = MDF_OK;

	subdev_port_t *subdev = calloc(1, sizeof(subdev_port_t));
	subdev->port_index = 0; // 0 is reserved for device itself
	subdev->protocol = SUBDEV_PROTOCOL_NONE;
	subdev->poll_interval = 100;
	subdev->cids_num = 0;
	subdev->cids = calloc(DEVICE_CID_MAX_NUM, sizeof(subdev_cid_t));
	subdev_cid_t cid;
	ret = mlink_subdev_cid_init(&cid, DEVICE_CID_DO01, 1.0, CONST_STR_FORMAT_I32, 0, 1, "");
	cid.value.value_i32 = 0;
	if(ret == ESP_OK)mlink_add_subdev_cid(subdev, &cid);
	ret = mlink_subdev_cid_init(&cid, DEVICE_CID_DO02, 1.0, CONST_STR_FORMAT_I32, 0, 1, "");
	cid.value.value_i32 = 0;
	if(ret == ESP_OK)mlink_add_subdev_cid(subdev, &cid);
	ret = mlink_subdev_cid_init(&cid, DEVICE_CID_DO03, 1.0, CONST_STR_FORMAT_I32, 0, 1, "");
	cid.value.value_i32 = 0;
	if(ret == ESP_OK)mlink_add_subdev_cid(subdev, &cid);
	ret = mlink_subdev_cid_init(&cid, DEVICE_CID_DO04, 1.0, CONST_STR_FORMAT_I32, 0, 1, "");
	cid.value.value_i32 = 0;
	if(ret == ESP_OK)mlink_add_subdev_cid(subdev, &cid);

	ret = mlink_subdev_cid_init(&cid, DEVICE_CID_DI01, 1.0, CONST_STR_FORMAT_I32, 0, 1, "");
	cid.value.value_i32 = 1;
	if(ret == ESP_OK)mlink_add_subdev_cid(subdev, &cid);
	ret = mlink_subdev_cid_init(&cid, DEVICE_CID_DI02, 1.0, CONST_STR_FORMAT_I32, 0, 1, "");
	cid.value.value_i32 = 1;
	if(ret == ESP_OK)mlink_add_subdev_cid(subdev, &cid);
	ret = mlink_subdev_cid_init(&cid, DEVICE_CID_DI03, 1.0, CONST_STR_FORMAT_I32, 0, 1, "");
	cid.value.value_i32 = 1;
	if(ret == ESP_OK)mlink_add_subdev_cid(subdev, &cid);
	ret = mlink_subdev_cid_init(&cid, DEVICE_CID_DI04, 1.0, CONST_STR_FORMAT_I32, 0, 1, "");
	cid.value.value_i32 = 1;
	if(ret == ESP_OK)mlink_add_subdev_cid(subdev, &cid);

	ret = mlink_subdev_cid_init(&cid, DEVICE_CID_AI01, 1.0, CONST_STR_FORMAT_FLOAT, 0, 1, "");
	if(ret == ESP_OK)mlink_add_subdev_cid(subdev, &cid);
	ret = mlink_subdev_cid_init(&cid, DEVICE_CID_AI02, 1.0, CONST_STR_FORMAT_FLOAT, 0, 1, "");
	if(ret == ESP_OK)mlink_add_subdev_cid(subdev, &cid);
	ret = mlink_subdev_cid_init(&cid, DEVICE_CID_AI03, 1.0, CONST_STR_FORMAT_FLOAT, 0, 1, "");
	if(ret == ESP_OK)mlink_add_subdev_cid(subdev, &cid);

	ret = mlink_subdev_cid_init(&cid, DEVICE_CID_TEMPERATURE, 1.0, CONST_STR_FORMAT_FLOAT, 0, 1, "");
	cid.value.value_float = 25.0;
	if(ret == ESP_OK)mlink_add_subdev_cid(subdev, &cid);

	ret = mlink_subdev_cid_init(&cid, DEVICE_CID_BAT_VOLTAGE, 1.0, CONST_STR_FORMAT_FLOAT, 0, 0, "");
	cid.value.value_float = 3.7;
	if(ret == ESP_OK)mlink_add_subdev_cid(subdev, &cid);

	ret = mlink_subdev_cid_init(&cid, DEVICE_CID_BAT_LEVEL, 1.0, CONST_STR_FORMAT_FLOAT, 0, 10, "");
	cid.value.value_float = 100.0;
	if(ret == ESP_OK)mlink_add_subdev_cid(subdev, &cid);

	ret = mlink_subdev_cid_init(&cid, DEVICE_CID_POWER_SOURCE, 1.0, CONST_STR_FORMAT_I32, 0, 1, "");
	if(ret == ESP_OK)mlink_add_subdev_cid(subdev, &cid);

	mlink_add_subdev(subdev);

	return ret;
}
#endif
